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 */
33 * -------------------------------------------------------------------
37 * -------------------------------------------------------------------
41 KTreeViewItem::KTreeViewItem(const QString
& theText
) :
46 delayedExpanding(false),
57 // constructor that takes a pixmap
58 KTreeViewItem::KTreeViewItem(const QString
& theText
,
59 const QPixmap
& thePixmap
) :
64 delayedExpanding(false),
77 KTreeViewItem::~KTreeViewItem()
80 // remove the children
81 KTreeViewItem
* i
= child
;
90 // appends a direct child
91 void KTreeViewItem::appendChild(KTreeViewItem
* newChild
)
93 newChild
->parent
= this;
94 newChild
->setOwner(owner
);
99 KTreeViewItem
* lastChild
= getChild();
100 while (lastChild
->hasSibling()) {
101 lastChild
= lastChild
->getSibling();
103 lastChild
->sibling
= newChild
;
105 newChild
->sibling
= 0;
109 // returns the bounding rectangle of the item content (not including indent
110 // and branches) for hit testing
111 QRect
KTreeViewItem::boundingRect(int indent
) const
113 const QFontMetrics
& fm
= owner
->fontMetrics();
116 int rectW
= width(indent
, fm
) - rectX
;
117 int rectH
= height(fm
);
118 return QRect(rectX
, rectY
, rectW
, rectH
);
121 // returns the child item at the specified index
122 KTreeViewItem
* KTreeViewItem::childAt(int index
) const
126 KTreeViewItem
* item
= getChild();
127 while (index
> 0 && item
!= 0) {
128 item
= item
->getSibling();
134 // returns the number of children this item has
135 uint
KTreeViewItem::childCount() const
140 /* returns the index of the given child item in this item's branch */
141 int KTreeViewItem::childIndex(KTreeViewItem
* searched
) const
143 assert(searched
!= 0);
145 KTreeViewItem
* item
= getChild();
146 while (item
!= 0 && item
!= searched
) {
147 item
= item
->getSibling();
150 return item
== 0 ? -1 : index
;
153 // indicates whether mouse press is in expand button
154 inline bool KTreeViewItem::expandButtonClicked(const QPoint
& coord
) const
156 return expandButton
.contains(coord
);
159 // returns a pointer to first child item
160 KTreeViewItem
* KTreeViewItem::getChild() const
165 // returns the parent of this item
166 KTreeViewItem
* KTreeViewItem::getParent() const
171 // returns reference to the item pixmap
172 const QPixmap
& KTreeViewItem::getPixmap() const
177 // returns the sibling below this item
178 KTreeViewItem
* KTreeViewItem::getSibling() const
183 // returns a pointer to the item text
184 const QString
& KTreeViewItem::getText() const
189 // indicates whether this item has any children
190 bool KTreeViewItem::hasChild() const
195 // indicates whether this item has a parent
196 bool KTreeViewItem::hasParent() const
201 // indicates whether this item has a sibling below it
202 bool KTreeViewItem::hasSibling() const
207 int KTreeViewItem::height() const
210 return height(owner
->fontMetrics());
213 // returns the maximum height of text and pixmap including margins
214 int KTreeViewItem::height(const QFontMetrics
& fm
) const
216 int maxHeight
= pixmap
.height();
217 int textHeight
= fm
.height();
218 maxHeight
= textHeight
> maxHeight
? textHeight
: maxHeight
;
219 return maxHeight
+ 4;
222 // inserts child item at specified index in branch
223 void KTreeViewItem::insertChild(int index
, KTreeViewItem
* newChild
)
226 appendChild(newChild
);
229 newChild
->parent
= this;
230 newChild
->setOwner(owner
);
232 newChild
->sibling
= getChild();
236 KTreeViewItem
* prevItem
= getChild();
237 KTreeViewItem
* nextItem
= prevItem
->getSibling();
238 while (--index
> 0 && nextItem
) {
240 nextItem
= prevItem
->getSibling();
242 prevItem
->sibling
= newChild
;
243 newChild
->sibling
= nextItem
;
248 // indicates whether this item is displayed expanded
249 // NOTE: a TRUE response does not necessarily indicate the item
251 bool KTreeViewItem::isExpanded() const
256 // returns true if all ancestors are expanded
257 bool KTreeViewItem::isVisible() const
259 for (KTreeViewItem
* p
= getParent(); p
!= 0; p
= p
->getParent()) {
260 if (!p
->isExpanded())
266 bool KTreeViewItem::keyEvent(QKeyEvent
* /*ev*/)
268 return false; /* not handled */
271 bool KTreeViewItem::mouseEvent(QMouseEvent
* /*ev*/, const QPoint
& /*itemCoord*/)
273 return false; /* not handled */
276 // paint this item, including tree branches and expand button
277 void KTreeViewItem::paint(QPainter
* p
, int indent
, const QColorGroup
& cg
,
278 bool highlighted
) const
280 assert(getParent() != 0); /* can't paint root item */
285 int cellHeight
= height(p
->fontMetrics());
288 paintTree(p
, indent
, cellHeight
, cg
);
292 * If this item has at least one child and expand button drawing is
293 * enabled, set the rect for the expand button for later mouse press
294 * bounds checking, and draw the button.
296 if (doExpandButton
&& (child
|| delayedExpanding
)) {
297 paintExpandButton(p
, indent
, cellHeight
, cg
);
300 // now draw the item pixmap and text, if applicable
301 int pixmapX
= indent
;
302 int pixmapY
= (cellHeight
- pixmap
.height()) / 2;
303 p
->drawPixmap(pixmapX
, pixmapY
, pixmap
);
306 paintText(p
, indent
, cellHeight
, cg
, highlighted
);
311 void KTreeViewItem::paintExpandButton(QPainter
* p
, int indent
, int cellHeight
,
312 const QColorGroup
& cg
) const
314 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
315 int cellCenterY
= cellHeight
/ 2;
317 QRect
paintRect(parentLeaderX
- 4, cellCenterY
- 4, 9, 9);
318 p
->setBrush(cg
.base());
319 p
->setPen(cg
.foreground());
320 p
->drawRect(paintRect
);
322 p
->drawLine(parentLeaderX
- 2, cellCenterY
,
323 parentLeaderX
+ 2, cellCenterY
);
325 p
->drawLine(parentLeaderX
- 2, cellCenterY
,
326 parentLeaderX
+ 2, cellCenterY
);
327 p
->drawLine(parentLeaderX
, cellCenterY
- 2,
328 parentLeaderX
, cellCenterY
+ 2);
330 p
->setBrush(NoBrush
);
333 * The area that the user can click to collapse and expand the tree is
334 * somewhat larger than the painted expand button.
336 expandButton
.setRect(indent
- owner
->itemIndent
, 0,
337 owner
->itemIndent
, cellHeight
);
340 // paint the highlight
341 void KTreeViewItem::paintHighlight(QPainter
* p
, int indent
, const QColorGroup
& colorGroup
,
345 fc
= colorGroup
.text();
346 QRect textRect
= textBoundingRect(indent
);
348 textRect
.coords(&l
, &t
, &r
, &b
);
350 outerRect
.setCoords(l
- 2, t
- 2, r
+ 2, b
+ 2);
352 p
->fillRect(textRect
, fc
); /* highlight background */
354 p
->drawRect(outerRect
);
356 p
->fillRect(outerRect
, fc
); /* highlight background */
360 // draw the text, highlighted if requested
361 void KTreeViewItem::paintText(QPainter
* p
, int indent
, int cellHeight
,
362 const QColorGroup
& cg
, bool highlighted
) const
364 int textX
= indent
+ pixmap
.width() + 3;
365 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
366 p
->fontMetrics().ascent();
369 paintHighlight(p
, indent
, cg
, owner
->hasFocus());
370 p
->setPen(cg
.base());
371 p
->setBackgroundColor(cg
.text());
374 p
->setPen(cg
.text());
375 p
->setBackgroundColor(cg
.base());
377 p
->drawText(textX
, textY
, text
);
380 // paint the tree structure
381 void KTreeViewItem::paintTree(QPainter
* p
, int indent
, int cellHeight
,
382 const QColorGroup
& cg
) const
384 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
385 int cellCenterY
= cellHeight
/ 2;
386 int cellBottomY
= cellHeight
- 1;
387 int itemLeaderX
= indent
- 1;
389 p
->setPen(cg
.background());
392 * If this is not the first item in the tree draw the line up
393 * towards parent or sibling.
395 if (parent
->parent
!= 0 || parent
->getChild() != this)
396 p
->drawLine(parentLeaderX
, 0, parentLeaderX
, cellCenterY
);
398 // draw the line down towards sibling
400 p
->drawLine(parentLeaderX
, cellCenterY
, parentLeaderX
, cellBottomY
);
403 * If this item has children or siblings in the tree or is a child of
404 * an item other than the root item then draw the little line from the
405 * item out to the left.
407 if (sibling
|| (doExpandButton
&& (child
|| delayedExpanding
)) ||
408 parent
->parent
!= 0 ||
410 * The following handles the case of an item at the end of the
411 * topmost level which doesn't have children.
413 parent
->getChild() != this)
415 p
->drawLine(parentLeaderX
, cellCenterY
, itemLeaderX
, cellCenterY
);
419 * If there are siblings of ancestors below, draw our portion of the
420 * branches that extend through this cell.
422 KTreeViewItem
* prevRoot
= parent
;
423 while (prevRoot
->getParent() != 0) { /* while not root item */
424 assert(prevRoot
->owner
== owner
);
425 if (prevRoot
->hasSibling()) {
426 int sibLeaderX
= owner
->indentation(prevRoot
) - (owner
->itemIndent
/ 2);
427 p
->drawLine(sibLeaderX
, 0, sibLeaderX
, cellBottomY
);
429 prevRoot
= prevRoot
->getParent();
433 // removes the given (direct) child from the branch
434 bool KTreeViewItem::removeChild(KTreeViewItem
* theChild
)
436 // search item in list of children
437 KTreeViewItem
* prevItem
= 0;
438 KTreeViewItem
* toRemove
= getChild();
439 while (toRemove
&& toRemove
!= theChild
) {
441 toRemove
= toRemove
->getSibling();
447 child
= toRemove
->getSibling();
449 prevItem
->sibling
= toRemove
->getSibling();
452 toRemove
->setOwner(0);
454 assert((numChildren
== 0) == (child
== 0));
456 return toRemove
!= 0;
459 // sets the delayed-expanding flag
460 void KTreeViewItem::setDelayedExpanding(bool flag
)
462 delayedExpanding
= flag
;
465 // tells the item whether it shall delete child items
466 void KTreeViewItem::setDeleteChildren(bool flag
)
468 deleteChildren
= flag
;
471 // sets the draw expand button flag of this item
472 void KTreeViewItem::setDrawExpandButton(bool doit
)
474 doExpandButton
= doit
;
477 // sets the draw text flag of this item
478 void KTreeViewItem::setDrawText(bool doit
)
483 // sets the draw tree branch flag of this item
484 void KTreeViewItem::setDrawTree(bool doit
)
489 // sets the expanded flag of this item
490 void KTreeViewItem::setExpanded(bool is
)
495 // sets the owner of this item and its children siblings
496 void KTreeViewItem::setOwner(KTreeView
* newOwner
, bool includeSiblings
)
498 /* Note: set owner of children's siblings! */
501 getChild()->setOwner(newOwner
, true);
502 if (includeSiblings
&& getSibling())
503 getSibling()->setOwner(newOwner
, true);
506 // sets the item pixmap to the given pixmap
507 void KTreeViewItem::setPixmap(const QPixmap
& pm
)
512 // sets the item text to the given string
513 void KTreeViewItem::setText(const QString
& t
)
518 // counts the child items and stores the result in numChildren
519 void KTreeViewItem::synchNumChildren()
522 KTreeViewItem
* item
= getChild();
525 item
= item
->getSibling();
530 * returns the bounding rect of the item text in cell coordinates couldn't
531 * get QFontMetrics::boundingRect() to work right so I made my own
533 QRect
KTreeViewItem::textBoundingRect(int indent
) const
535 const QFontMetrics
& fm
= owner
->fontMetrics();
536 int cellHeight
= height(fm
);
537 int rectX
= indent
+ pixmap
.width() + 2;
538 int rectY
= (cellHeight
- fm
.height()) / 2;
539 int rectW
= fm
.width(text
) + 2;
540 int rectH
= fm
.height();
541 return QRect(rectX
, rectY
, rectW
, rectH
);
544 // returns the total width of text and pixmap, including margins, spacing
545 // and indent, or -1 if empty -- SHOULD NEVER BE -1!
546 int KTreeViewItem::width(int indent
) const
548 return width(indent
, owner
->fontMetrics());
551 // The width of an item is composed of the following:
552 // - indentation (indent with times level)
554 // - 2 pixels for highlight border
558 // - 2 pixels for highlight border
559 int KTreeViewItem::width(int indent
, const QFontMetrics
& fm
) const
561 return indent
+ pixmap
.width() + fm
.width(text
) + 6;
566 * -------------------------------------------------------------------
570 * -------------------------------------------------------------------
574 KTreeView::KTreeView(QWidget
*parent
,
577 TableView(parent
, name
, f
),
580 drawExpandButton(true),
586 moveCurrentToSibling(false),
589 rubberband_mode(false)
593 setBackgroundColor(colorGroup().base());
595 treeRoot
= new KTreeViewItem
;
596 treeRoot
->setExpanded(true);
597 treeRoot
->owner
= this;
599 visibleItems
= new KTreeViewItem
*[itemCapacity
];
600 // clear those pointers
601 for (int j
= itemCapacity
-1; j
>= 0; j
--) {
607 KTreeView::~KTreeView()
611 delete[] visibleItems
;
615 // appends a child to the item at the given index with the given text
617 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
620 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
621 item
->setDeleteChildren(true);
622 appendChildItem(item
, index
);
625 // appends a child to the item at the end of the given path with
626 // the given text and pixmap
627 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
628 const KPath
& thePath
)
630 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
631 item
->setDeleteChildren(true);
632 appendChildItem(item
, thePath
);
635 // appends the given item to the children of the item at the given index
636 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, int index
)
638 /* find parent item and append new item to parent's sub tree */
639 KTreeViewItem
* parentItem
= itemAt(index
);
642 appendChildItem(parentItem
, newItem
);
645 // appends the given item to the children of the item at the end of the
647 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, const KPath
& thePath
)
649 /* find parent item and append new item to parent's sub tree */
650 KTreeViewItem
* parentItem
= itemAt(thePath
);
653 appendChildItem(parentItem
, newItem
);
656 // translate mouse coord to cell coord
657 QPoint
KTreeView::cellCoords(int row
, const QPoint
& widgetCoord
)
659 int cellX
= 0, cellY
= 0;
661 rowYPos(row
, &cellY
);
662 return QPoint(widgetCoord
.x() - cellX
, widgetCoord
.y() - cellY
);
665 // find item at specified index and change pixmap and/or text
666 void KTreeView::changeItem(const char *newText
,
667 const QPixmap
*newPixmap
,
670 KTreeViewItem
*item
= itemAt(index
);
672 changeItem(item
, index
, newText
, newPixmap
);
675 // find item at end of specified path, and change pixmap and/or text
676 void KTreeView::changeItem(const char* newText
,
677 const QPixmap
* newPixmap
,
678 const KPath
& thePath
)
680 KTreeViewItem
* item
= itemAt(thePath
);
682 int index
= itemRow(item
);
683 changeItem(item
, index
, newText
, newPixmap
);
687 // clear all items from list and erase display
688 void KTreeView::clear()
692 /* somewhat of a hack for takeItem so it doesn't update the current item... */
695 bool autoU
= autoUpdate();
696 setAutoUpdate(FALSE
);
697 QStack
<KTreeViewItem
> stack
;
698 stack
.push(treeRoot
);
699 while(!stack
.isEmpty()) {
700 KTreeViewItem
*item
= stack
.pop();
701 if(item
->hasChild()) {
703 stack
.push(item
->getChild());
705 else if(item
->hasSibling()) {
707 stack
.push(item
->getSibling());
709 else if(item
->getParent() != 0) {
715 if(goingDown
|| QApplication::closingDown())
717 setAutoUpdate(autoU
);
718 if(autoU
&& isVisible())
722 // return a count of all the items in the tree, whether visible or not
723 uint
KTreeView::count()
726 forEveryItem(&KTreeView::countItem
, (void *)&total
);
730 // returns the index of the current (highlighted) item
731 int KTreeView::currentItem() const
736 // collapses the item at the specified row index.
737 void KTreeView::collapseItem(int index
, bool emitSignal
)
739 KTreeViewItem
* item
= itemAt(index
);
741 collapseSubTree(item
, emitSignal
);
744 // expands the item at the specified row indes.
745 void KTreeView::expandItem(int index
, bool emitSignal
)
747 KTreeViewItem
* item
= itemAt(index
);
749 expandSubTree(item
, emitSignal
);
752 // returns the depth the tree is automatically expanded to when
754 int KTreeView::expandLevel() const
759 // visits every item in the tree, visible or not and applies
760 // the user supplied function with the item and user data passed as parameters
761 // if user supplied function returns true, traversal ends and function returns
762 bool KTreeView::forEveryItem(KForEveryFunc func
, void* user
, KTreeViewItem
* item
)
767 assert(item
->owner
== this);
768 item
= item
->getChild();
771 // visit the siblings
772 if ((*func
)(item
, user
)) {
775 // visit the children (recursively)
776 if (item
->hasChild()) {
777 if (forEveryItem(func
, user
, item
))
780 item
= item
->getSibling();
785 // visits every visible item in the tree in order and applies the
786 // user supplied function with the item and user data passed as parameters
787 // if user supplied function returns TRUE, traversal ends and function
789 bool KTreeView::forEveryVisibleItem(KForEveryFunc func
, void *user
,
795 // children are invisible (hence, nothing to do)
796 // if item is invisible or collapsed
797 if (!item
->isVisible() || !item
->isExpanded()) {
801 assert(item
->owner
== this);
802 item
= item
->getChild();
805 // visit the siblings
806 if ((*func
)(item
, user
)) {
809 // visit the children (recursively)
810 if (item
->hasChild() && item
->isExpanded()) {
811 if (forEveryVisibleItem(func
, user
, item
))
814 item
= item
->getSibling();
819 // returns a pointer to the KTreeViewItem at the current index
820 // or 0 if no current item
821 KTreeViewItem
*KTreeView::getCurrentItem()
823 if(current
== -1) return 0;
824 return itemAt(current
);
827 // returns the current indent spacing
828 int KTreeView::indentSpacing()
833 // inserts a new item with the specified text and pixmap before
834 // or after the item at the given index, depending on the value
836 // if index is negative, appends item to tree at root level
837 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
838 int row
, bool prefix
)
840 KTreeViewItem
* refItem
= itemAt(row
);
842 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
843 item
->setDeleteChildren(true);
845 bool success
= insertItem(refItem
, item
, prefix
);
851 // inserts a new item with the specified text and pixmap before
852 // or after the item at the end of the given path, depending on the value
854 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
855 const KPath
& path
, bool prefix
)
857 KTreeViewItem
* refItem
= itemAt(path
);
859 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
860 item
->setDeleteChildren(true);
862 bool success
= insertItem(refItem
, item
, prefix
);
868 // inserts the given item or derived object into the tree before
869 // or after the item at the given index, depending on the value
871 // if index is negative, appends item to tree at root level
872 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
873 int index
, bool prefix
)
875 // find the item currently at the index, if there is one
876 KTreeViewItem
* refItem
= itemAt(index
);
878 // insert new item at the appropriate place
879 return insertItem(refItem
, newItem
, prefix
);
882 // inserts the given item or derived object into the tree before
883 // or after the item at the end of the given path, depending on the value
885 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
886 const KPath
& thePath
, bool prefix
)
888 // find the item currently at the end of the path, if there is one
889 KTreeViewItem
* refItem
= itemAt(thePath
);
891 // insert new item at appropriate place
892 return insertItem(refItem
, newItem
, prefix
);
896 * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
899 KTreeViewItem
* KTreeView::itemAt(int row
) const
901 if (row
< 0 || row
>= numRows()) {
905 // lookup the item in the list of visible items
906 assert(row
< itemCapacity
);
907 KTreeViewItem
* i
= visibleItems
[row
];
913 // returns pointer to KTreeViewItem at the end of the
914 // path or 0 if not found
915 KTreeViewItem
* KTreeView::itemAt(const KPath
& path
)
920 // need a copy of the path because recursiveFind will destroy it
922 pathCopy
.setAutoDelete(false);
925 return recursiveFind(pathCopy
);
928 // computes the path of the item at the specified index
929 // if index is invalid, nothing is done.
930 void KTreeView::itemPath(int row
, KPath
& path
)
932 KTreeViewItem
* item
= itemAt(row
);
934 itemPath(item
, path
);
938 // returns the row in the visible tree of the given item or
940 int KTreeView::itemRow(KTreeViewItem
* item
)
942 if (item
->owner
== this) {
943 // search in list of visible items
944 for (int i
= numRows()-1; i
>= 0; i
--) {
945 if (visibleItems
[i
] == item
) {
955 * move the subtree at the specified index up one branch level (make root
956 * item a sibling of its current parent)
958 void KTreeView::join(int index
)
960 KTreeViewItem
*item
= itemAt(index
);
966 * move the subtree at the specified index up one branch level (make root
967 * item a sibling of it's current parent)
969 void KTreeView::join(const KPath
& path
)
971 KTreeViewItem
*item
= itemAt(path
);
976 /* move item at specified index one slot down in its parent's sub tree */
977 void KTreeView::lowerItem(int index
)
979 KTreeViewItem
*item
= itemAt(index
);
984 /* move item at specified path one slot down in its parent's sub tree */
985 void KTreeView::lowerItem(const KPath
& path
)
987 KTreeViewItem
* item
= itemAt(path
);
992 /* move item at specified index one slot up in its parent's sub tree */
993 void KTreeView::raiseItem(int index
)
995 KTreeViewItem
* item
= itemAt(index
);
1000 /* move item at specified path one slot up in its parent's sub tree */
1001 void KTreeView::raiseItem(const KPath
& path
)
1003 KTreeViewItem
* item
= itemAt(path
);
1008 // remove the item at the specified index and delete it
1009 void KTreeView::removeItem(int index
)
1011 KTreeViewItem
*item
= itemAt(index
);
1018 // remove the item at the end of the specified path and delete it
1019 void KTreeView::removeItem(const KPath
& thePath
)
1021 KTreeViewItem
* item
= itemAt(thePath
);
1028 void KTreeView::scrollVisible(KTreeViewItem
* item
, bool children
)
1032 int row
= itemRow(item
);
1034 return; /* do nothing if invisible */
1036 if (children
&& item
->isExpanded()) {
1037 // we are concerned about children
1038 if (!rowIsVisible(row
)) {
1039 // just move to the top
1042 // this is the complicated part
1043 // count the visible children (including grandchildren)
1045 forEveryVisibleItem(countItem
, &numVisible
, item
);
1046 // if the last child is visible, do nothing
1047 if (rowIsVisible(row
+ numVisible
))
1050 * Basically, item will become the top cell; but if there are
1051 * more visible rows in the widget than we have children, then
1052 * we don't move that far.
1054 int remain
= lastRowVisible()-topCell()-numVisible
;
1058 setTopCell(QMAX(0,row
-remain
));
1062 // we are not concerned about children
1063 if (rowIsVisible(row
))
1065 // just move the item to the top
1070 // sets the current item and hightlights it, emitting signals
1071 void KTreeView::setCurrentItem(int row
)
1075 int numVisible
= numRows();
1076 if (row
> numVisible
)
1078 int oldCurrent
= current
;
1080 if (oldCurrent
< numVisible
)
1081 updateCell(oldCurrent
, 0);
1083 updateCell(current
, 0, false);
1084 emit
highlighted(current
);
1088 // enables/disables drawing of expand button
1089 void KTreeView::setExpandButtonDrawing(bool enable
)
1091 if (drawExpandButton
== enable
)
1093 drawExpandButton
= enable
;
1095 // the user parameter is cast to a bool in setItemExpandButtonDrawing
1096 forEveryItem(&KTreeView::setItemExpandButtonDrawing
, enable
? &enable
: 0);
1098 if (autoUpdate() && isVisible())
1102 // sets depth to which subtrees are automatically expanded, and
1103 // redraws tree if auto update enabled
1104 void KTreeView::setExpandLevel(int level
)
1106 if (expansion
== level
)
1109 KTreeViewItem
* item
= getCurrentItem();
1110 forEveryItem(&KTreeView::setItemExpandLevel
, 0);
1112 if (item
->getParent()->isExpanded())
1114 item
= item
->getParent();
1117 setCurrentItem(itemRow(item
));
1118 if (autoUpdate() && isVisible())
1122 // sets the indent margin for all branches and repaints if auto update enabled
1123 void KTreeView::setIndentSpacing(int spacing
)
1125 if (itemIndent
== spacing
)
1127 itemIndent
= spacing
;
1129 if (autoUpdate() && isVisible())
1133 void KTreeView::setMoveCurrentToSibling(bool m
)
1135 moveCurrentToSibling
= m
;
1138 // enables/disables display of item text (keys)
1139 void KTreeView::setShowItemText(bool enable
)
1141 if (showText
== enable
)
1145 // the user parameter is cast to a bool in setItemShowText
1146 forEveryItem(&KTreeView::setItemShowText
, enable
? &enable
: 0);
1148 if (autoUpdate() && isVisible())
1152 // enables/disables tree branch drawing
1153 void KTreeView::setTreeDrawing(bool enable
)
1155 if (drawTree
== enable
)
1159 // the user parameter is cast to a bool in setItemTreeDrawing
1160 forEveryItem(&KTreeView::setItemTreeDrawing
, enable
? &enable
: 0);
1162 if (autoUpdate() && isVisible())
1166 // indicates whether item text keys are displayed
1167 bool KTreeView::showItemText() const
1172 // indents the item at the given index, splitting the tree into
1174 void KTreeView::split(int index
)
1176 KTreeViewItem
*item
= itemAt(index
);
1181 // indents the item at the given path, splitting the tree into
1183 void KTreeView::split(const KPath
& path
)
1185 KTreeViewItem
* item
= itemAt(path
);
1190 // removes item at specified index from tree but does not delete it
1191 // returns pointer to the item or 0 if not succesful
1192 KTreeViewItem
*KTreeView::takeItem(int index
)
1194 KTreeViewItem
*item
= itemAt(index
);
1200 // removes item at specified path from tree but does not delete it
1201 // returns pointer to the item or 0 if not successful
1202 KTreeViewItem
* KTreeView::takeItem(const KPath
& path
)
1204 KTreeViewItem
* item
= itemAt(path
);
1210 // indicates whether tree branches are drawn
1211 bool KTreeView::treeDrawing() const
1217 // appends a child to the specified parent item (note: a child, not a sibling, is added!)
1218 void KTreeView::appendChildItem(KTreeViewItem
* theParent
,
1219 KTreeViewItem
* newItem
)
1221 theParent
->appendChild(newItem
);
1224 newItem
->setDrawExpandButton(drawExpandButton
);
1225 newItem
->setDrawTree(drawTree
);
1226 newItem
->setDrawText(showText
);
1227 if (level(newItem
) < expansion
) {
1228 newItem
->setExpanded(true);
1231 // fix up branch levels of any children that the new item may already have
1232 if(newItem
->hasChild()) {
1233 fixChildren(newItem
);
1236 // if necessary, adjust cell width, number of rows and repaint
1237 if (newItem
->isVisible() || theParent
->childCount() == 1) {
1238 bool autoU
= autoUpdate();
1239 setAutoUpdate(false);
1240 updateVisibleItems();
1241 setAutoUpdate(autoU
);
1242 if (autoU
&& isVisible())
1247 // returns the height of the cell(row) at the specified row (index)
1248 int KTreeView::cellHeight(int row
) const
1250 return itemAt(row
)->height(fontMetrics());
1253 // returns the width of the cells. Note: this is mostly for derived classes
1254 // which have more than 1 column
1255 int KTreeView::cellWidth(int /*col*/) const
1257 return maxItemWidth
;
1260 // changes the given item with the new text and/or pixmap
1261 void KTreeView::changeItem(KTreeViewItem
* toChange
, int itemRow
,
1262 const char* newText
, const QPixmap
* newPixmap
)
1264 int indent
= indentation(toChange
);
1265 int oldWidth
= toChange
->width(indent
);
1267 toChange
->setText(newText
);
1269 toChange
->setPixmap(*newPixmap
);
1270 if(oldWidth
!= toChange
->width(indent
))
1274 if(autoUpdate() && rowIsVisible(itemRow
))
1275 updateCell(itemRow
, 0);
1278 // collapses the subtree at the specified item
1279 void KTreeView::collapseSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1281 assert(subRoot
->owner
== this);
1282 if (!subRoot
->isExpanded())
1285 // must move the current item if it is visible
1286 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1288 subRoot
->setExpanded(false);
1289 if (subRoot
->isVisible()) {
1290 bool autoU
= autoUpdate();
1291 setAutoUpdate(false);
1292 updateVisibleItems();
1293 // re-seat current item
1295 setCurrentItem(itemRow(cur
));
1298 emit
collapsed(itemRow(subRoot
));
1300 setAutoUpdate(autoU
);
1301 if (autoU
&& isVisible())
1306 // used by count() with forEach() function to count total number
1307 // of items in the tree
1308 bool KTreeView::countItem(KTreeViewItem
*, void* total
)
1310 int* t
= static_cast<int*>(total
);
1315 // expands the subtree at the given item
1316 void KTreeView::expandSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1318 assert(subRoot
->owner
== this);
1319 if (subRoot
->isExpanded())
1322 // must move the current item if it is visible
1323 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1327 if (subRoot
->delayedExpanding
) {
1328 emit
expanding(subRoot
, allow
);
1333 subRoot
->setExpanded(true);
1335 if (subRoot
->isVisible()) {
1336 bool autoU
= autoUpdate();
1337 setAutoUpdate(false);
1338 updateVisibleItems();
1339 // re-seat current item
1341 setCurrentItem(itemRow(cur
));
1344 emit
expanded(itemRow(subRoot
));
1346 setAutoUpdate(autoU
);
1347 if (autoU
&& isVisible())
1352 // fix up branch levels out of whack from split/join operations on the tree
1353 void KTreeView::fixChildren(KTreeViewItem
*parentItem
)
1355 KTreeViewItem
* childItem
= 0;
1356 KTreeViewItem
* siblingItem
= 0;
1357 // int childBranch = parentItem->getBranch() + 1;
1358 if(parentItem
->hasChild()) {
1359 childItem
= parentItem
->getChild();
1360 // childItem->setBranch(childBranch);
1361 childItem
->owner
= parentItem
->owner
;
1362 fixChildren(childItem
);
1364 while(childItem
&& childItem
->hasSibling()) {
1365 siblingItem
= childItem
->getSibling();
1366 // siblingItem->setBranch(childBranch);
1367 siblingItem
->owner
= parentItem
->owner
;
1368 fixChildren(siblingItem
);
1369 childItem
= siblingItem
;
1374 * Handle QFocusEvent processing by setting current item to top row if
1375 * there is no current item, and updates cell to add or delete the focus
1376 * rectangle on the highlight bar. The base class is not called because it
1377 * does a repaint() which causes flicker.
1379 void KTreeView::focusInEvent(QFocusEvent
*)
1381 if (current
< 0 && numRows() > 0)
1382 setCurrentItem(topCell());
1383 updateCell(current
, 0);
1386 void KTreeView::focusOutEvent(QFocusEvent
*)
1388 updateCell(current
, 0);
1391 // called by updateCellWidth() for each item in the visible list
1392 bool KTreeView::getMaxItemWidth(KTreeViewItem
* item
, void* user
)
1394 assert(item
->owner
!= 0);
1395 int indent
= item
->owner
->indentation(item
);
1396 int* maxW
= static_cast<int*>(user
);
1397 int w
= item
->width(indent
);
1403 int KTreeView::indentation(KTreeViewItem
* item
) const
1405 return level(item
) * itemIndent
+ itemIndent
+ 3;
1408 // inserts the new item before or after the reference item, depending
1409 // on the value of prefix
1410 bool KTreeView::insertItem(KTreeViewItem
* referenceItem
,
1411 KTreeViewItem
* newItem
,
1414 assert(newItem
!= 0);
1415 assert(referenceItem
== 0 || referenceItem
->owner
== this);
1417 /* set the new item's state */
1418 newItem
->setDrawExpandButton(drawExpandButton
);
1419 newItem
->setDrawTree(drawTree
);
1420 newItem
->setDrawText(showText
);
1421 KTreeViewItem
* parentItem
;
1422 if (referenceItem
) {
1423 parentItem
= referenceItem
->getParent();
1424 int insertIndex
= parentItem
->childIndex(referenceItem
);
1427 parentItem
->insertChild(insertIndex
, newItem
);
1430 // no reference item, append at end of visible tree
1432 parentItem
= treeRoot
;
1433 parentItem
->appendChild(newItem
);
1436 // set item expansion
1437 if (level(newItem
) < expansion
)
1438 newItem
->setExpanded(true);
1440 // fix up branch levels of any children
1441 if (newItem
->hasChild())
1442 fixChildren(newItem
);
1444 // if repaint necessary, do it if visible and auto update
1446 if (newItem
->isVisible() || parentItem
->childCount() == 1) {
1447 bool autoU
= autoUpdate();
1448 setAutoUpdate(FALSE
);
1449 updateVisibleItems();
1450 setAutoUpdate(autoU
);
1451 if (autoU
&& isVisible())
1458 * returns pointer to item's path
1460 void KTreeView::itemPath(KTreeViewItem
* item
, KPath
& path
) const
1463 assert(item
->owner
== this);
1464 if (item
!= treeRoot
) {
1465 itemPath(item
->getParent(), path
);
1466 path
.push(new QString(item
->getText()));
1471 * joins the item's branch into the tree, making the item a sibling of its
1474 void KTreeView::join(KTreeViewItem
*item
)
1476 KTreeViewItem
*itemParent
= item
->getParent();
1477 if(itemParent
->hasParent()) {
1478 bool autoU
= autoUpdate();
1479 setAutoUpdate(FALSE
);
1481 insertItem(itemParent
, item
, FALSE
);
1482 setAutoUpdate(autoU
);
1483 if(autoU
&& isVisible())
1488 // handles keyboard interface
1489 void KTreeView::keyPressEvent(QKeyEvent
* e
)
1492 return; /* nothing to do */
1494 /* if there's no current item, make the top item current */
1495 if (currentItem() < 0)
1496 setCurrentItem(topCell());
1497 assert(currentItem() >= 0); /* we need a current item */
1498 assert(itemAt(currentItem()) != 0); /* we really need a current item */
1500 // give currentItem a chance to handle the event
1501 if (itemAt(currentItem())->keyEvent(e
))
1502 return; /* handled */
1504 int pageSize
, delta
;
1505 KTreeViewItem
* item
;
1510 // make previous item current, scroll up if necessary
1511 if (currentItem() > 0) {
1512 setCurrentItem(currentItem() - 1);
1513 scrollVisible(itemAt(currentItem()), false);
1517 // make next item current, scroll down if necessary
1518 if (currentItem() < numRows() - 1) {
1519 setCurrentItem(currentItem() + 1);
1520 if (currentItem() > lastRowVisible()) {
1521 // scrollVisible is not feasible here because
1522 // it scrolls the item to the top
1523 setTopCell(topCell() + currentItem() - lastRowVisible());
1524 } else if (currentItem() < topCell()) {
1525 setTopCell(currentItem());
1530 // move highlight one page down and scroll down
1531 delta
= currentItem() - topCell();
1532 pageSize
= lastRowVisible() - topCell();
1533 setTopCell(QMIN(topCell() + pageSize
, numRows() - 1));
1534 setCurrentItem(QMIN(topCell() + delta
, numRows() - 1));
1537 // move highlight one page up and scroll up
1538 delta
= currentItem() - topCell();
1539 pageSize
= lastRowVisible() - topCell();
1540 setTopCell(QMAX(topCell() - pageSize
, 0));
1541 setCurrentItem(QMAX(topCell() + delta
, 0));
1545 // if current item has subtree and is collapsed, expand it
1546 item
= itemAt(currentItem());
1547 if (item
->isExpanded() && item
->hasChild() && key
== Key_Right
) {
1548 // going right on an expanded item is like going down
1552 expandSubTree(item
, true);
1553 scrollVisible(item
, true);
1558 // if current item has subtree and is expanded, collapse it
1559 item
= itemAt(currentItem());
1560 if ((!item
->isExpanded() || !item
->hasChild()) && key
== Key_Left
) {
1561 // going left on a collapsed item goes to its parent
1562 item
= item
->getParent();
1563 if (item
== treeRoot
)
1564 break; /* we're already at the top */
1565 assert(item
->isVisible());
1566 setCurrentItem(itemRow(item
));
1568 collapseSubTree(item
, true);
1570 scrollVisible(item
, false);
1574 // select the current item
1575 if (currentItem() >= 0)
1576 emit
selected(currentItem());
1583 // handles keyboard interface
1584 void KTreeView::keyReleaseEvent(QKeyEvent
* e
)
1586 if (currentItem() >= 0 && itemAt(currentItem()) != 0)
1587 itemAt(currentItem())->keyEvent(e
);
1590 int KTreeView::level(KTreeViewItem
* item
) const
1593 assert(item
->owner
== this);
1594 assert(item
!= treeRoot
);
1596 item
= item
->parent
->parent
; /* since item != treeRoot, there is a parent */
1598 item
= item
->parent
;
1604 /* move specified item down one slot in parent's subtree */
1605 void KTreeView::lowerItem(KTreeViewItem
*item
)
1607 KTreeViewItem
*itemParent
= item
->getParent();
1608 uint itemChildIndex
= itemParent
->childIndex(item
);
1609 if(itemChildIndex
< itemParent
->childCount() - 1) {
1610 bool autoU
= autoUpdate();
1611 setAutoUpdate(FALSE
);
1613 insertItem(itemParent
->childAt(itemChildIndex
), item
, FALSE
);
1614 setAutoUpdate(autoU
);
1615 if(autoU
&& isVisible())
1620 // handle mouse double click events by selecting the clicked item
1621 // and emitting the signal
1622 void KTreeView::mouseDoubleClickEvent(QMouseEvent
* e
)
1624 // find out which row has been clicked
1625 int itemClicked
= findRow(e
->y());
1627 if (itemClicked
< 0)
1628 return; /* invalid row, do nothing */
1630 KTreeViewItem
* item
= itemAt(itemClicked
);
1634 // translate mouse coord to cell coord
1635 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1638 if (item
->mouseEvent(e
, cellCoord
))
1642 int indent
= indentation(item
);
1643 if (item
->boundingRect(indent
).contains(cellCoord
))
1644 emit
selected(itemClicked
);
1647 // handle mouse movement events
1648 void KTreeView::mouseMoveEvent(QMouseEvent
* e
)
1650 // in rubberband_mode we actually scroll the window now
1651 if (rubberband_mode
) {
1652 move_rubberband(e
->pos());
1654 // else forward to current item
1655 int current
= currentItem();
1656 if (current
>= 0 && itemAt(current
))
1657 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1662 // handle single mouse presses
1663 void KTreeView::mousePressEvent(QMouseEvent
* e
)
1665 /* first: cancel rubberbanding if it's on */
1666 if (rubberband_mode
)
1668 // another button was pressed while rubberbanding, stop the move.
1669 // RB: if we allow other buttons while rubberbanding the tree can expand
1670 // while rubberbanding - we then need to recalculate and resize the
1671 // rubberband rect and show the new size
1676 // find out which row has been clicked
1677 int itemClicked
= findRow(e
->y());
1679 // nothing to do if not on valid row
1680 if (itemClicked
< 0)
1682 KTreeViewItem
* item
= itemAt(itemClicked
);
1686 // translate mouse coord to cell coord
1687 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1689 // give the item a crack
1690 if (item
->mouseEvent(e
, cellCoord
))
1691 return; /* event eaten by item */
1693 // check for rubberbanding
1694 if (e
->button() == MidButton
)
1696 // RB: the MMB is hardcoded to the "rubberband" scroll mode
1697 if (!rubberband_mode
) {
1698 start_rubberband(e
->pos());
1703 if (e
->button() == RightButton
) {
1704 emit
rightPressed(itemClicked
, e
->pos());
1706 /* hit test expand button (doesn't set currentItem) */
1707 else if (item
->expandButtonClicked(cellCoord
)) {
1708 if (item
->isExpanded()) {
1709 collapseSubTree(item
, true);
1711 expandSubTree(item
, true);
1712 scrollVisible(item
, true); /* make children visible */
1716 else if (item
->boundingRect(indentation(item
)).contains(cellCoord
)) {
1717 setCurrentItem(itemClicked
);
1721 // handle mouse release events
1722 void KTreeView::mouseReleaseEvent(QMouseEvent
*e
)
1724 /* if it's the MMB end rubberbanding */
1725 if (rubberband_mode
) {
1726 if (e
->button() == MidButton
)
1730 // forward to current item
1731 int current
= currentItem();
1732 if (current
>= 0 && itemAt(current
))
1733 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1736 // rubberband move: draw the rubberband
1737 void KTreeView::draw_rubberband()
1740 * RB: I'm using a white pen because of the XorROP mode. I would prefer
1741 * to draw the rectangle in red but I don't now how to get a pen which
1742 * draws red in XorROP mode (this depends on the background). In fact
1743 * the color should be configurable.
1746 if (!rubberband_mode
) return;
1747 QPainter
paint(this);
1748 paint
.setPen(white
);
1749 paint
.setRasterOp(XorROP
);
1750 paint
.drawRect(xOffset()*viewWidth()/totalWidth(),
1751 yOffset()*viewHeight()/totalHeight(),
1752 rubber_width
+1, rubber_height
+1);
1756 // rubberband move: start move
1757 void KTreeView::start_rubberband(const QPoint
& where
)
1759 if (rubberband_mode
) { // Oops!
1762 /* RB: Don't now, if this check is necessary */
1763 if (!viewWidth() || !viewHeight()) return;
1764 if (!totalWidth() || !totalHeight()) return;
1766 // calculate the size of the rubberband rectangle
1767 rubber_width
= viewWidth()*viewWidth()/totalWidth();
1768 if (rubber_width
> viewWidth()) rubber_width
= viewWidth();
1769 rubber_height
= viewHeight()*viewHeight()/totalHeight();
1770 if (rubber_height
> viewHeight()) rubber_height
= viewHeight();
1772 // remember the cursor position and the actual offset
1773 rubber_startMouse
= where
;
1774 rubber_startX
= xOffset();
1775 rubber_startY
= yOffset();
1776 rubberband_mode
=TRUE
;
1780 // rubberband move: end move
1781 void KTreeView::end_rubberband()
1783 if (!rubberband_mode
) return;
1785 rubberband_mode
= FALSE
;
1788 // rubberband move: hanlde mouse moves
1789 void KTreeView::move_rubberband(const QPoint
& where
)
1791 if (!rubberband_mode
) return;
1793 // look how much the mouse moved and calc the new scroll position
1794 QPoint delta
= where
- rubber_startMouse
;
1795 int nx
= rubber_startX
+ delta
.x() * totalWidth() / viewWidth();
1796 int ny
= rubber_startY
+ delta
.y() * totalHeight() / viewHeight();
1798 // check the new position (and make it valid)
1800 else if (nx
> maxXOffset()) nx
= maxXOffset();
1802 else if (ny
> maxYOffset()) ny
= maxYOffset();
1804 // redraw the rubberband at the new position
1811 // paints the cell at the specified row and col
1812 // col is ignored for now since there is only one
1813 void KTreeView::paintCell(QPainter
* p
, int row
, int)
1815 KTreeViewItem
* item
= itemAt(row
);
1819 QColorGroup cg
= colorGroup();
1820 int indent
= indentation(item
);
1821 item
->paint(p
, indent
, cg
,
1822 current
== row
); /* highlighted */
1826 /* This is needed to make the kcontrol's color setup working (Marcin Dalecki) */
1827 void KTreeView::paletteChange(const QPalette
&)
1829 setBackgroundColor(colorGroup().base());
1834 /* raise the specified item up one slot in parent's subtree */
1835 void KTreeView::raiseItem(KTreeViewItem
*item
)
1837 KTreeViewItem
*itemParent
= item
->getParent();
1838 int itemChildIndex
= itemParent
->childIndex(item
);
1839 if(itemChildIndex
> 0) {
1840 bool autoU
= autoUpdate();
1841 setAutoUpdate(FALSE
);
1843 insertItem(itemParent
->childAt(--itemChildIndex
), item
, TRUE
);
1844 setAutoUpdate(autoU
);
1845 if(autoU
&& isVisible())
1850 // find the item at the path
1851 KTreeViewItem
* KTreeView::recursiveFind(KPath
& path
)
1857 QString
* searchString
= path
.pop();
1859 // find the parent item
1860 KTreeViewItem
* parent
= recursiveFind(path
);
1865 * Iterate through the parent's children searching for searchString.
1867 KTreeViewItem
* sibling
= parent
->getChild();
1868 while (sibling
!= 0) {
1869 if (*searchString
== sibling
->getText()) {
1870 break; /* found it! */
1872 sibling
= sibling
->getSibling();
1877 void KTreeView::setItemExpanded(KTreeViewItem
* item
)
1879 if (level(item
) < expansion
) {
1880 expandSubTree(item
, true);
1882 collapseSubTree(item
, true);
1886 // called by setExpandLevel for each item in tree
1887 bool KTreeView::setItemExpandLevel(KTreeViewItem
* item
, void*)
1889 assert(item
->owner
!= 0);
1890 item
->owner
->setItemExpanded(item
);
1894 // called by setExpandButtonDrawing for every item in tree
1895 // the parameter drawButton is used as (and implicitly cast to) a bool
1896 bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem
* item
,
1899 item
->setDrawExpandButton(drawButton
);
1903 // called by setShowItemText for every item in tree
1904 // the parameter newDrawText is used as (and implicitly cast to) a bool
1905 bool KTreeView::setItemShowText(KTreeViewItem
* item
,
1908 item
->setDrawText(newDrawText
);
1912 // called by setTreeDrawing for every item in tree
1913 // the parameter drawTree is used as (and implicitly cast to) a bool
1914 bool KTreeView::setItemTreeDrawing(KTreeViewItem
* item
, void* drawTree
)
1916 item
->setDrawTree(drawTree
);
1920 // makes the item a child of the item above it, splitting
1921 // the tree into a new branch
1922 void KTreeView::split(KTreeViewItem
*item
)
1924 KTreeViewItem
*itemParent
= item
->getParent();
1925 int itemChildIndex
= itemParent
->childIndex(item
);
1926 if(itemChildIndex
== 0)
1928 bool autoU
= autoUpdate();
1929 setAutoUpdate(FALSE
);
1931 appendChildItem(itemParent
->childAt(--itemChildIndex
), item
);
1932 setAutoUpdate(autoU
);
1933 if(autoU
&& isVisible())
1937 // removes the item from the tree without deleting it
1938 void KTreeView::takeItem(KTreeViewItem
* item
)
1940 assert(item
->owner
== this);
1942 // TODO: go over this function again
1944 bool wasVisible
= item
->isVisible();
1946 * If we have a current item, make sure that it is not in the subtree
1947 * that we are about to remove. If the current item is in the part
1948 * below the taken-out subtree, we must move it up a number of rows if
1949 * the taken-out subtree is at least partially visible.
1951 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1952 KTreeViewItem
* oldCurrent
= cur
;
1953 if (wasVisible
&& cur
!= 0) {
1954 KTreeViewItem
* c
= cur
;
1955 while (c
!= 0 && c
!= item
) {
1959 // move current item to parent
1960 cur
= item
->getParent();
1961 if (cur
== treeRoot
) {
1963 // move it to next or previous sibling
1964 if (moveCurrentToSibling
) {
1965 if (item
->getSibling() != 0) {
1966 cur
= item
->getSibling();
1967 } else if (treeRoot
->getChild() != item
) {
1968 cur
= treeRoot
->getChild();
1969 while (cur
!= 0 && cur
->getSibling() != item
)
1970 cur
= cur
->getSibling();
1976 KTreeViewItem
* parentItem
= item
->getParent();
1977 parentItem
->removeChild(item
);
1979 if (wasVisible
|| parentItem
->childCount() == 0) {
1980 bool autoU
= autoUpdate();
1981 setAutoUpdate(FALSE
);
1982 updateVisibleItems();
1983 setAutoUpdate(autoU
);
1984 if (autoU
&& isVisible())
1988 // re-seat the current item
1989 // row changes if cur is below the taken item
1990 current
= cur
!= 0 ? itemRow(cur
) : -1;
1991 // signal must be emitted only if item really changed
1992 if (cur
!= oldCurrent
) {
1993 updateCell(current
, 0, false);
1994 emit
highlighted(current
);
1998 // visits each item, calculates the maximum width
1999 // and updates TableView
2000 void KTreeView::updateCellWidth()
2002 // make cells at least 1 pixel wide to avoid singularities (division by zero)
2004 forEveryVisibleItem(&KTreeView::getMaxItemWidth
, &maxW
);
2005 maxItemWidth
= maxW
;
2009 int xoff
= xOffset();
2010 int yoff
= yOffset();
2011 if (xoff
> maxXOffset()) xoff
= maxXOffset();
2012 if (yoff
> maxYOffset()) yoff
= maxYOffset();
2014 setOffset(xoff
, yoff
);
2017 void KTreeView::updateVisibleItems()
2021 updateVisibleItemRec(treeRoot
, index
, count
);
2022 assert(index
== count
);
2027 void KTreeView::updateVisibleItemRec(KTreeViewItem
* item
, int& index
, int& count
)
2029 if (!item
->isExpanded()) {
2030 // no visible items if not expanded
2035 * Record the children of item in the list of visible items.
2037 * Don't register item itself, it's already in the list. Also only
2038 * allocate new space for children.
2040 count
+= item
->childCount();
2041 if (count
> itemCapacity
) {
2043 int newCapacity
= itemCapacity
;
2045 newCapacity
+= newCapacity
;
2046 } while (newCapacity
< count
);
2047 KTreeViewItem
** newItems
= new KTreeViewItem
*[newCapacity
];
2048 // clear the unneeded space
2049 for (int i
= index
; i
< newCapacity
; i
++) {
2052 // move already accumulated items over
2053 for (int i
= index
-1; i
>= 0; i
--) {
2054 newItems
[i
] = visibleItems
[i
];
2056 delete[] visibleItems
;
2057 visibleItems
= newItems
;
2058 itemCapacity
= newCapacity
;
2061 for (KTreeViewItem
* i
= item
->getChild(); i
!= 0; i
= i
->getSibling()) {
2062 visibleItems
[index
++] = i
;
2063 updateVisibleItemRec(i
, index
, count
);