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),
58 // constructor that takes a pixmap
59 KTreeViewItem::KTreeViewItem(const QString
& theText
,
60 const QPixmap
& thePixmap
) :
65 delayedExpanding(false),
78 KTreeViewItem::~KTreeViewItem()
81 // remove the children
82 KTreeViewItem
* i
= child
;
91 // appends a direct child
92 void KTreeViewItem::appendChild(KTreeViewItem
* newChild
)
94 newChild
->parent
= this;
95 newChild
->setOwner(owner
);
100 KTreeViewItem
* lastChild
= getChild();
101 while (lastChild
->hasSibling()) {
102 lastChild
= lastChild
->getSibling();
104 lastChild
->sibling
= newChild
;
106 newChild
->sibling
= 0;
110 // returns the bounding rectangle of the item content (not including indent
111 // and branches) for hit testing
112 QRect
KTreeViewItem::boundingRect(int indent
) const
114 const QFontMetrics
& fm
= owner
->fontMetrics();
117 int rectW
= width(indent
, fm
) - rectX
;
118 int rectH
= height(fm
);
119 return QRect(rectX
, rectY
, rectW
, rectH
);
122 // returns the child item at the specified index
123 KTreeViewItem
* KTreeViewItem::childAt(int index
) const
127 KTreeViewItem
* item
= getChild();
128 while (index
> 0 && item
!= 0) {
129 item
= item
->getSibling();
135 // returns the number of children this item has
136 uint
KTreeViewItem::childCount() const
141 /* returns the index of the given child item in this item's branch */
142 int KTreeViewItem::childIndex(KTreeViewItem
* searched
) const
144 assert(searched
!= 0);
146 KTreeViewItem
* item
= getChild();
147 while (item
!= 0 && item
!= searched
) {
148 item
= item
->getSibling();
151 return item
== 0 ? -1 : index
;
154 // indicates whether mouse press is in expand button
155 inline bool KTreeViewItem::expandButtonClicked(const QPoint
& coord
) const
157 return expandButton
.contains(coord
);
160 // returns a pointer to first child item
161 KTreeViewItem
* KTreeViewItem::getChild() const
166 // returns the parent of this item
167 KTreeViewItem
* KTreeViewItem::getParent() const
172 // returns reference to the item pixmap
173 const QPixmap
& KTreeViewItem::getPixmap() const
178 // returns the sibling below this item
179 KTreeViewItem
* KTreeViewItem::getSibling() const
184 // returns a pointer to the item text
185 const QString
& KTreeViewItem::getText() const
190 // indicates whether this item has any children
191 bool KTreeViewItem::hasChild() const
196 // indicates whether this item has a parent
197 bool KTreeViewItem::hasParent() const
202 // indicates whether this item has a sibling below it
203 bool KTreeViewItem::hasSibling() const
208 int KTreeViewItem::height() const
211 return height(owner
->fontMetrics());
214 // returns the maximum height of text and pixmap including margins
215 int KTreeViewItem::height(const QFontMetrics
& fm
) const
217 int maxHeight
= pixmap
.height();
218 int textHeight
= fm
.height();
219 maxHeight
= textHeight
> maxHeight
? textHeight
: maxHeight
;
220 return maxHeight
+ 4;
223 // inserts child item at specified index in branch
224 void KTreeViewItem::insertChild(int index
, KTreeViewItem
* newChild
)
227 appendChild(newChild
);
230 newChild
->parent
= this;
231 newChild
->setOwner(owner
);
233 newChild
->sibling
= getChild();
237 KTreeViewItem
* prevItem
= getChild();
238 KTreeViewItem
* nextItem
= prevItem
->getSibling();
239 while (--index
> 0 && nextItem
) {
241 nextItem
= prevItem
->getSibling();
243 prevItem
->sibling
= newChild
;
244 newChild
->sibling
= nextItem
;
249 // indicates whether this item is displayed expanded
250 // NOTE: a TRUE response does not necessarily indicate the item
252 bool KTreeViewItem::isExpanded() const
257 // returns true if all ancestors are expanded
258 bool KTreeViewItem::isVisible() const
260 for (KTreeViewItem
* p
= getParent(); p
!= 0; p
= p
->getParent()) {
261 if (!p
->isExpanded())
267 bool KTreeViewItem::keyEvent(QKeyEvent
* /*ev*/)
269 return false; /* not handled */
272 bool KTreeViewItem::mouseEvent(QMouseEvent
* /*ev*/, const QPoint
& /*itemCoord*/)
274 return false; /* not handled */
277 // paint this item, including tree branches and expand button
278 void KTreeViewItem::paint(QPainter
* p
, int indent
, const QColorGroup
& cg
,
279 bool highlighted
) const
281 assert(getParent() != 0); /* can't paint root item */
286 int cellHeight
= height(p
->fontMetrics());
289 paintTree(p
, indent
, cellHeight
, cg
);
293 * If this item has at least one child and expand button drawing is
294 * enabled, set the rect for the expand button for later mouse press
295 * bounds checking, and draw the button.
297 if (doExpandButton
&& (child
|| delayedExpanding
)) {
298 paintExpandButton(p
, indent
, cellHeight
, cg
);
301 // now draw the item pixmap and text, if applicable
302 int pixmapX
= indent
;
303 int pixmapY
= (cellHeight
- pixmap
.height()) / 2;
304 p
->drawPixmap(pixmapX
, pixmapY
, pixmap
);
307 paintText(p
, indent
, cellHeight
, cg
, highlighted
);
312 void KTreeViewItem::paintExpandButton(QPainter
* p
, int indent
, int cellHeight
,
313 const QColorGroup
& cg
) const
315 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
316 int cellCenterY
= cellHeight
/ 2;
318 QRect
paintRect(parentLeaderX
- 4, cellCenterY
- 4, 9, 9);
319 p
->setBrush(cg
.base());
320 p
->setPen(cg
.foreground());
321 p
->drawRect(paintRect
);
323 p
->drawLine(parentLeaderX
- 2, cellCenterY
,
324 parentLeaderX
+ 2, cellCenterY
);
326 p
->drawLine(parentLeaderX
- 2, cellCenterY
,
327 parentLeaderX
+ 2, cellCenterY
);
328 p
->drawLine(parentLeaderX
, cellCenterY
- 2,
329 parentLeaderX
, cellCenterY
+ 2);
331 p
->setBrush(NoBrush
);
334 * The area that the user can click to collapse and expand the tree is
335 * somewhat larger than the painted expand button.
337 expandButton
.setRect(indent
- owner
->itemIndent
, 0,
338 owner
->itemIndent
, cellHeight
);
341 // paint the highlight
342 void KTreeViewItem::paintHighlight(QPainter
* p
, int indent
, const QColorGroup
& colorGroup
,
346 fc
= colorGroup
.text();
347 QRect textRect
= textBoundingRect(indent
);
349 textRect
.coords(&l
, &t
, &r
, &b
);
351 outerRect
.setCoords(l
- 2, t
- 2, r
+ 2, b
+ 2);
353 p
->fillRect(textRect
, fc
); /* highlight background */
355 p
->drawRect(outerRect
);
357 p
->fillRect(outerRect
, fc
); /* highlight background */
361 // draw the text, highlighted if requested
362 void KTreeViewItem::paintText(QPainter
* p
, int indent
, int cellHeight
,
363 const QColorGroup
& cg
, bool highlighted
) const
365 int textX
= indent
+ pixmap
.width() + 3;
366 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
367 p
->fontMetrics().ascent();
370 paintHighlight(p
, indent
, cg
, owner
->hasFocus());
371 p
->setPen(cg
.base());
372 p
->setBackgroundColor(cg
.text());
375 p
->setPen(cg
.text());
376 p
->setBackgroundColor(cg
.base());
378 p
->drawText(textX
, textY
, text
);
381 // paint the tree structure
382 void KTreeViewItem::paintTree(QPainter
* p
, int indent
, int cellHeight
,
383 const QColorGroup
& cg
) const
385 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
386 int cellCenterY
= cellHeight
/ 2;
387 int cellBottomY
= cellHeight
- 1;
388 int itemLeaderX
= indent
- 1;
390 p
->setPen(cg
.background());
393 * If this is not the first item in the tree draw the line up
394 * towards parent or sibling.
396 if (parent
->parent
!= 0 || parent
->getChild() != this)
397 p
->drawLine(parentLeaderX
, 0, parentLeaderX
, cellCenterY
);
399 // draw the line down towards sibling
401 p
->drawLine(parentLeaderX
, cellCenterY
, parentLeaderX
, cellBottomY
);
404 * If this item has children or siblings in the tree or is a child of
405 * an item other than the root item then draw the little line from the
406 * item out to the left.
408 if (sibling
|| (doExpandButton
&& (child
|| delayedExpanding
)) ||
409 parent
->parent
!= 0 ||
411 * The following handles the case of an item at the end of the
412 * topmost level which doesn't have children.
414 parent
->getChild() != this)
416 p
->drawLine(parentLeaderX
, cellCenterY
, itemLeaderX
, cellCenterY
);
420 * If there are siblings of ancestors below, draw our portion of the
421 * branches that extend through this cell.
423 KTreeViewItem
* prevRoot
= parent
;
424 while (prevRoot
->getParent() != 0) { /* while not root item */
425 assert(prevRoot
->owner
== owner
);
426 if (prevRoot
->hasSibling()) {
427 int sibLeaderX
= owner
->indentation(prevRoot
) - (owner
->itemIndent
/ 2);
428 p
->drawLine(sibLeaderX
, 0, sibLeaderX
, cellBottomY
);
430 prevRoot
= prevRoot
->getParent();
434 // removes the given (direct) child from the branch
435 bool KTreeViewItem::removeChild(KTreeViewItem
* theChild
)
437 // search item in list of children
438 KTreeViewItem
* prevItem
= 0;
439 KTreeViewItem
* toRemove
= getChild();
440 while (toRemove
&& toRemove
!= theChild
) {
442 toRemove
= toRemove
->getSibling();
448 child
= toRemove
->getSibling();
450 prevItem
->sibling
= toRemove
->getSibling();
453 toRemove
->setOwner(0);
455 assert((numChildren
== 0) == (child
== 0));
457 return toRemove
!= 0;
460 // sets the delayed-expanding flag
461 void KTreeViewItem::setDelayedExpanding(bool flag
)
463 delayedExpanding
= flag
;
466 // tells the item whether it shall delete child items
467 void KTreeViewItem::setDeleteChildren(bool flag
)
469 deleteChildren
= flag
;
472 // sets the draw expand button flag of this item
473 void KTreeViewItem::setDrawExpandButton(bool doit
)
475 doExpandButton
= doit
;
478 // sets the draw text flag of this item
479 void KTreeViewItem::setDrawText(bool doit
)
484 // sets the draw tree branch flag of this item
485 void KTreeViewItem::setDrawTree(bool doit
)
490 // sets the expanded flag of this item
491 void KTreeViewItem::setExpanded(bool is
)
496 // sets the owner of this item and its children siblings
497 void KTreeViewItem::setOwner(KTreeView
* newOwner
, bool includeSiblings
)
499 /* Note: set owner of children's siblings! */
502 getChild()->setOwner(newOwner
, true);
503 if (includeSiblings
&& getSibling())
504 getSibling()->setOwner(newOwner
, true);
507 // sets the item pixmap to the given pixmap
508 void KTreeViewItem::setPixmap(const QPixmap
& pm
)
513 // sets the item text to the given string
514 void KTreeViewItem::setText(const QString
& t
)
519 // counts the child items and stores the result in numChildren
520 void KTreeViewItem::synchNumChildren()
523 KTreeViewItem
* item
= getChild();
526 item
= item
->getSibling();
531 * returns the bounding rect of the item text in cell coordinates couldn't
532 * get QFontMetrics::boundingRect() to work right so I made my own
534 QRect
KTreeViewItem::textBoundingRect(int indent
) const
536 const QFontMetrics
& fm
= owner
->fontMetrics();
537 int cellHeight
= height(fm
);
538 int rectX
= indent
+ pixmap
.width() + 2;
539 int rectY
= (cellHeight
- fm
.height()) / 2;
540 int rectW
= fm
.width(text
) + 2;
541 int rectH
= fm
.height();
542 return QRect(rectX
, rectY
, rectW
, rectH
);
545 // returns the total width of text and pixmap, including margins, spacing
546 // and indent, or -1 if empty -- SHOULD NEVER BE -1!
547 int KTreeViewItem::width(int indent
) const
549 return width(indent
, owner
->fontMetrics());
552 // The width of an item is composed of the following:
553 // - indentation (indent with times level)
555 // - 2 pixels for highlight border
559 // - 2 pixels for highlight border
560 int KTreeViewItem::width(int indent
, const QFontMetrics
& fm
) const
562 return indent
+ pixmap
.width() + fm
.width(text
) + 6;
567 * -------------------------------------------------------------------
571 * -------------------------------------------------------------------
575 KTreeView::KTreeView(QWidget
*parent
,
578 TableView(parent
, name
, f
),
581 drawExpandButton(true),
587 moveCurrentToSibling(false),
590 rubberband_mode(false)
594 setBackgroundColor(colorGroup().base());
596 treeRoot
= new KTreeViewItem
;
597 treeRoot
->setExpanded(true);
598 treeRoot
->owner
= this;
600 visibleItems
= new KTreeViewItem
*[itemCapacity
];
601 // clear those pointers
602 for (int j
= itemCapacity
-1; j
>= 0; j
--) {
608 KTreeView::~KTreeView()
612 delete[] visibleItems
;
616 // appends a child to the item at the given index with the given text
618 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
621 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
622 item
->setDeleteChildren(true);
623 appendChildItem(item
, index
);
626 // appends a child to the item at the end of the given path with
627 // the given text and pixmap
628 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
629 const KPath
& thePath
)
631 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
632 item
->setDeleteChildren(true);
633 appendChildItem(item
, thePath
);
636 // appends the given item to the children of the item at the given index
637 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, int index
)
639 /* find parent item and append new item to parent's sub tree */
640 KTreeViewItem
* parentItem
= itemAt(index
);
643 appendChildItem(parentItem
, newItem
);
646 // appends the given item to the children of the item at the end of the
648 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, const KPath
& thePath
)
650 /* find parent item and append new item to parent's sub tree */
651 KTreeViewItem
* parentItem
= itemAt(thePath
);
654 appendChildItem(parentItem
, newItem
);
657 // translate mouse coord to cell coord
658 QPoint
KTreeView::cellCoords(int row
, const QPoint
& widgetCoord
)
660 int cellX
= 0, cellY
= 0;
662 rowYPos(row
, &cellY
);
663 return QPoint(widgetCoord
.x() - cellX
, widgetCoord
.y() - cellY
);
666 // find item at specified index and change pixmap and/or text
667 void KTreeView::changeItem(const char *newText
,
668 const QPixmap
*newPixmap
,
671 KTreeViewItem
*item
= itemAt(index
);
673 changeItem(item
, index
, newText
, newPixmap
);
676 // find item at end of specified path, and change pixmap and/or text
677 void KTreeView::changeItem(const char* newText
,
678 const QPixmap
* newPixmap
,
679 const KPath
& thePath
)
681 KTreeViewItem
* item
= itemAt(thePath
);
683 int index
= itemRow(item
);
684 changeItem(item
, index
, newText
, newPixmap
);
688 // clear all items from list and erase display
689 void KTreeView::clear()
693 /* somewhat of a hack for takeItem so it doesn't update the current item... */
696 bool autoU
= autoUpdate();
697 setAutoUpdate(FALSE
);
698 QStack
<KTreeViewItem
> stack
;
699 stack
.push(treeRoot
);
700 while(!stack
.isEmpty()) {
701 KTreeViewItem
*item
= stack
.pop();
702 if(item
->hasChild()) {
704 stack
.push(item
->getChild());
706 else if(item
->hasSibling()) {
708 stack
.push(item
->getSibling());
710 else if(item
->getParent() != 0) {
716 if(goingDown
|| QApplication::closingDown())
718 setAutoUpdate(autoU
);
719 if(autoU
&& isVisible())
723 // return a count of all the items in the tree, whether visible or not
724 uint
KTreeView::count()
727 forEveryItem(&KTreeView::countItem
, (void *)&total
);
731 // returns the index of the current (highlighted) item
732 int KTreeView::currentItem() const
737 // collapses the item at the specified row index.
738 void KTreeView::collapseItem(int index
, bool emitSignal
)
740 KTreeViewItem
* item
= itemAt(index
);
742 collapseSubTree(item
, emitSignal
);
745 // expands the item at the specified row indes.
746 void KTreeView::expandItem(int index
, bool emitSignal
)
748 KTreeViewItem
* item
= itemAt(index
);
750 expandSubTree(item
, emitSignal
);
753 // returns the depth the tree is automatically expanded to when
755 int KTreeView::expandLevel() const
760 // visits every item in the tree, visible or not and applies
761 // the user supplied function with the item and user data passed as parameters
762 // if user supplied function returns true, traversal ends and function returns
763 bool KTreeView::forEveryItem(KForEveryFunc func
, void* user
, KTreeViewItem
* item
)
768 assert(item
->owner
== this);
769 item
= item
->getChild();
772 // visit the siblings
773 if ((*func
)(item
, user
)) {
776 // visit the children (recursively)
777 if (item
->hasChild()) {
778 if (forEveryItem(func
, user
, item
))
781 item
= item
->getSibling();
786 // visits every visible item in the tree in order and applies the
787 // user supplied function with the item and user data passed as parameters
788 // if user supplied function returns TRUE, traversal ends and function
790 bool KTreeView::forEveryVisibleItem(KForEveryFunc func
, void *user
,
796 // children are invisible (hence, nothing to do)
797 // if item is invisible or collapsed
798 if (!item
->isVisible() || !item
->isExpanded()) {
802 assert(item
->owner
== this);
803 item
= item
->getChild();
806 // visit the siblings
807 if ((*func
)(item
, user
)) {
810 // visit the children (recursively)
811 if (item
->hasChild() && item
->isExpanded()) {
812 if (forEveryVisibleItem(func
, user
, item
))
815 item
= item
->getSibling();
820 // returns a pointer to the KTreeViewItem at the current index
821 // or 0 if no current item
822 KTreeViewItem
*KTreeView::getCurrentItem()
824 if(current
== -1) return 0;
825 return itemAt(current
);
828 // returns the current indent spacing
829 int KTreeView::indentSpacing()
834 // inserts a new item with the specified text and pixmap before
835 // or after the item at the given index, depending on the value
837 // if index is negative, appends item to tree at root level
838 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
839 int row
, bool prefix
)
841 KTreeViewItem
* refItem
= itemAt(row
);
843 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
844 item
->setDeleteChildren(true);
846 bool success
= insertItem(refItem
, item
, prefix
);
852 // inserts a new item with the specified text and pixmap before
853 // or after the item at the end of the given path, depending on the value
855 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
856 const KPath
& path
, bool prefix
)
858 KTreeViewItem
* refItem
= itemAt(path
);
860 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
861 item
->setDeleteChildren(true);
863 bool success
= insertItem(refItem
, item
, prefix
);
869 // inserts the given item or derived object into the tree before
870 // or after the item at the given index, depending on the value
872 // if index is negative, appends item to tree at root level
873 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
874 int index
, bool prefix
)
876 // find the item currently at the index, if there is one
877 KTreeViewItem
* refItem
= itemAt(index
);
879 // insert new item at the appropriate place
880 return insertItem(refItem
, newItem
, prefix
);
883 // inserts the given item or derived object into the tree before
884 // or after the item at the end of the given path, depending on the value
886 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
887 const KPath
& thePath
, bool prefix
)
889 // find the item currently at the end of the path, if there is one
890 KTreeViewItem
* refItem
= itemAt(thePath
);
892 // insert new item at appropriate place
893 return insertItem(refItem
, newItem
, prefix
);
897 * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
900 KTreeViewItem
* KTreeView::itemAt(int row
) const
902 if (row
< 0 || row
>= numRows()) {
906 // lookup the item in the list of visible items
907 assert(row
< itemCapacity
);
908 KTreeViewItem
* i
= visibleItems
[row
];
914 // returns pointer to KTreeViewItem at the end of the
915 // path or 0 if not found
916 KTreeViewItem
* KTreeView::itemAt(const KPath
& path
)
921 // need a copy of the path because recursiveFind will destroy it
922 KPath pathCopy
= path
;
924 return recursiveFind(pathCopy
);
927 // computes the path of the item at the specified index
928 // if index is invalid, nothing is done.
929 void KTreeView::itemPath(int row
, KPath
& path
)
931 KTreeViewItem
* item
= itemAt(row
);
933 itemPath(item
, path
);
937 // returns the row in the visible tree of the given item or
939 int KTreeView::itemRow(KTreeViewItem
* item
)
941 if (item
->owner
== this) {
942 // search in list of visible items
943 for (int i
= numRows()-1; i
>= 0; i
--) {
944 if (visibleItems
[i
] == item
) {
954 * move the subtree at the specified index up one branch level (make root
955 * item a sibling of its current parent)
957 void KTreeView::join(int index
)
959 KTreeViewItem
*item
= itemAt(index
);
965 * move the subtree at the specified index up one branch level (make root
966 * item a sibling of it's current parent)
968 void KTreeView::join(const KPath
& path
)
970 KTreeViewItem
*item
= itemAt(path
);
975 /* move item at specified index one slot down in its parent's sub tree */
976 void KTreeView::lowerItem(int index
)
978 KTreeViewItem
*item
= itemAt(index
);
983 /* move item at specified path one slot down in its parent's sub tree */
984 void KTreeView::lowerItem(const KPath
& path
)
986 KTreeViewItem
* item
= itemAt(path
);
991 /* move item at specified index one slot up in its parent's sub tree */
992 void KTreeView::raiseItem(int index
)
994 KTreeViewItem
* item
= itemAt(index
);
999 /* move item at specified path one slot up in its parent's sub tree */
1000 void KTreeView::raiseItem(const KPath
& path
)
1002 KTreeViewItem
* item
= itemAt(path
);
1007 // remove the item at the specified index and delete it
1008 void KTreeView::removeItem(int index
)
1010 KTreeViewItem
*item
= itemAt(index
);
1017 // remove the item at the end of the specified path and delete it
1018 void KTreeView::removeItem(const KPath
& thePath
)
1020 KTreeViewItem
* item
= itemAt(thePath
);
1027 void KTreeView::scrollVisible(KTreeViewItem
* item
, bool children
)
1031 int row
= itemRow(item
);
1033 return; /* do nothing if invisible */
1035 if (children
&& item
->isExpanded()) {
1036 // we are concerned about children
1037 if (!rowIsVisible(row
)) {
1038 // just move to the top
1041 // this is the complicated part
1042 // count the visible children (including grandchildren)
1044 forEveryVisibleItem(countItem
, &numVisible
, item
);
1045 // if the last child is visible, do nothing
1046 if (rowIsVisible(row
+ numVisible
))
1049 * Basically, item will become the top cell; but if there are
1050 * more visible rows in the widget than we have children, then
1051 * we don't move that far.
1053 int remain
= lastRowVisible()-topCell()-numVisible
;
1057 setTopCell(QMAX(0,row
-remain
));
1061 // we are not concerned about children
1062 if (rowIsVisible(row
))
1064 // just move the item to the top
1069 // sets the current item and hightlights it, emitting signals
1070 void KTreeView::setCurrentItem(int row
)
1074 int numVisible
= numRows();
1075 if (row
> numVisible
)
1077 int oldCurrent
= current
;
1079 if (oldCurrent
< numVisible
)
1080 updateCell(oldCurrent
, 0);
1082 updateCell(current
, 0, false);
1083 emit
highlighted(current
);
1087 // enables/disables drawing of expand button
1088 void KTreeView::setExpandButtonDrawing(bool enable
)
1090 if (drawExpandButton
== enable
)
1092 drawExpandButton
= enable
;
1094 // the user parameter is cast to a bool in setItemExpandButtonDrawing
1095 forEveryItem(&KTreeView::setItemExpandButtonDrawing
, enable
? &enable
: 0);
1097 if (autoUpdate() && isVisible())
1101 // sets depth to which subtrees are automatically expanded, and
1102 // redraws tree if auto update enabled
1103 void KTreeView::setExpandLevel(int level
)
1105 if (expansion
== level
)
1108 KTreeViewItem
* item
= getCurrentItem();
1109 forEveryItem(&KTreeView::setItemExpandLevel
, 0);
1111 if (item
->getParent()->isExpanded())
1113 item
= item
->getParent();
1116 setCurrentItem(itemRow(item
));
1117 if (autoUpdate() && isVisible())
1121 // sets the indent margin for all branches and repaints if auto update enabled
1122 void KTreeView::setIndentSpacing(int spacing
)
1124 if (itemIndent
== spacing
)
1126 itemIndent
= spacing
;
1128 if (autoUpdate() && isVisible())
1132 void KTreeView::setMoveCurrentToSibling(bool m
)
1134 moveCurrentToSibling
= m
;
1137 // enables/disables display of item text (keys)
1138 void KTreeView::setShowItemText(bool enable
)
1140 if (showText
== enable
)
1144 // the user parameter is cast to a bool in setItemShowText
1145 forEveryItem(&KTreeView::setItemShowText
, enable
? &enable
: 0);
1147 if (autoUpdate() && isVisible())
1151 // enables/disables tree branch drawing
1152 void KTreeView::setTreeDrawing(bool enable
)
1154 if (drawTree
== enable
)
1158 // the user parameter is cast to a bool in setItemTreeDrawing
1159 forEveryItem(&KTreeView::setItemTreeDrawing
, enable
? &enable
: 0);
1161 if (autoUpdate() && isVisible())
1165 // indicates whether item text keys are displayed
1166 bool KTreeView::showItemText() const
1171 // indents the item at the given index, splitting the tree into
1173 void KTreeView::split(int index
)
1175 KTreeViewItem
*item
= itemAt(index
);
1180 // indents the item at the given path, splitting the tree into
1182 void KTreeView::split(const KPath
& path
)
1184 KTreeViewItem
* item
= itemAt(path
);
1189 // removes item at specified index from tree but does not delete it
1190 // returns pointer to the item or 0 if not succesful
1191 KTreeViewItem
*KTreeView::takeItem(int index
)
1193 KTreeViewItem
*item
= itemAt(index
);
1199 // removes item at specified path from tree but does not delete it
1200 // returns pointer to the item or 0 if not successful
1201 KTreeViewItem
* KTreeView::takeItem(const KPath
& path
)
1203 KTreeViewItem
* item
= itemAt(path
);
1209 // indicates whether tree branches are drawn
1210 bool KTreeView::treeDrawing() const
1216 // appends a child to the specified parent item (note: a child, not a sibling, is added!)
1217 void KTreeView::appendChildItem(KTreeViewItem
* theParent
,
1218 KTreeViewItem
* newItem
)
1220 theParent
->appendChild(newItem
);
1223 newItem
->setDrawExpandButton(drawExpandButton
);
1224 newItem
->setDrawTree(drawTree
);
1225 newItem
->setDrawText(showText
);
1226 if (level(newItem
) < expansion
) {
1227 newItem
->setExpanded(true);
1230 // fix up branch levels of any children that the new item may already have
1231 if(newItem
->hasChild()) {
1232 fixChildren(newItem
);
1235 // if necessary, adjust cell width, number of rows and repaint
1236 if (newItem
->isVisible() || theParent
->childCount() == 1) {
1237 bool autoU
= autoUpdate();
1238 setAutoUpdate(false);
1239 updateVisibleItems();
1240 setAutoUpdate(autoU
);
1241 if (autoU
&& isVisible())
1246 // returns the height of the cell(row) at the specified row (index)
1247 int KTreeView::cellHeight(int row
) const
1249 return itemAt(row
)->height(fontMetrics());
1252 // returns the width of the cells. Note: this is mostly for derived classes
1253 // which have more than 1 column
1254 int KTreeView::cellWidth(int /*col*/) const
1256 return maxItemWidth
;
1259 // changes the given item with the new text and/or pixmap
1260 void KTreeView::changeItem(KTreeViewItem
* toChange
, int itemRow
,
1261 const char* newText
, const QPixmap
* newPixmap
)
1263 int indent
= indentation(toChange
);
1264 int oldWidth
= toChange
->width(indent
);
1266 toChange
->setText(newText
);
1268 toChange
->setPixmap(*newPixmap
);
1269 if(oldWidth
!= toChange
->width(indent
))
1273 if(autoUpdate() && rowIsVisible(itemRow
))
1274 updateCell(itemRow
, 0);
1277 // collapses the subtree at the specified item
1278 void KTreeView::collapseSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1280 assert(subRoot
->owner
== this);
1281 if (!subRoot
->isExpanded())
1284 // must move the current item if it is visible
1285 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1287 subRoot
->setExpanded(false);
1288 if (subRoot
->isVisible()) {
1289 bool autoU
= autoUpdate();
1290 setAutoUpdate(false);
1291 updateVisibleItems();
1292 // re-seat current item
1294 setCurrentItem(itemRow(cur
));
1297 emit
collapsed(itemRow(subRoot
));
1299 setAutoUpdate(autoU
);
1300 if (autoU
&& isVisible())
1305 // used by count() with forEach() function to count total number
1306 // of items in the tree
1307 bool KTreeView::countItem(KTreeViewItem
*, void* total
)
1309 int* t
= static_cast<int*>(total
);
1314 // expands the subtree at the given item
1315 void KTreeView::expandSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1317 assert(subRoot
->owner
== this);
1318 if (subRoot
->isExpanded())
1321 // must move the current item if it is visible
1322 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1326 if (subRoot
->delayedExpanding
) {
1327 emit
expanding(subRoot
, allow
);
1332 subRoot
->setExpanded(true);
1334 if (subRoot
->isVisible()) {
1335 bool autoU
= autoUpdate();
1336 setAutoUpdate(false);
1337 updateVisibleItems();
1338 // re-seat current item
1340 setCurrentItem(itemRow(cur
));
1343 emit
expanded(itemRow(subRoot
));
1345 setAutoUpdate(autoU
);
1346 if (autoU
&& isVisible())
1351 // fix up branch levels out of whack from split/join operations on the tree
1352 void KTreeView::fixChildren(KTreeViewItem
*parentItem
)
1354 KTreeViewItem
* childItem
= 0;
1355 KTreeViewItem
* siblingItem
= 0;
1356 // int childBranch = parentItem->getBranch() + 1;
1357 if(parentItem
->hasChild()) {
1358 childItem
= parentItem
->getChild();
1359 // childItem->setBranch(childBranch);
1360 childItem
->owner
= parentItem
->owner
;
1361 fixChildren(childItem
);
1363 while(childItem
&& childItem
->hasSibling()) {
1364 siblingItem
= childItem
->getSibling();
1365 // siblingItem->setBranch(childBranch);
1366 siblingItem
->owner
= parentItem
->owner
;
1367 fixChildren(siblingItem
);
1368 childItem
= siblingItem
;
1373 * Handle QFocusEvent processing by setting current item to top row if
1374 * there is no current item, and updates cell to add or delete the focus
1375 * rectangle on the highlight bar. The base class is not called because it
1376 * does a repaint() which causes flicker.
1378 void KTreeView::focusInEvent(QFocusEvent
*)
1380 if (current
< 0 && numRows() > 0)
1381 setCurrentItem(topCell());
1382 updateCell(current
, 0);
1385 void KTreeView::focusOutEvent(QFocusEvent
*)
1387 updateCell(current
, 0);
1390 // called by updateCellWidth() for each item in the visible list
1391 bool KTreeView::getMaxItemWidth(KTreeViewItem
* item
, void* user
)
1393 assert(item
->owner
!= 0);
1394 int indent
= item
->owner
->indentation(item
);
1395 int* maxW
= static_cast<int*>(user
);
1396 int w
= item
->width(indent
);
1402 int KTreeView::indentation(KTreeViewItem
* item
) const
1404 return level(item
) * itemIndent
+ itemIndent
+ 3;
1407 // inserts the new item before or after the reference item, depending
1408 // on the value of prefix
1409 bool KTreeView::insertItem(KTreeViewItem
* referenceItem
,
1410 KTreeViewItem
* newItem
,
1413 assert(newItem
!= 0);
1414 assert(referenceItem
== 0 || referenceItem
->owner
== this);
1416 /* set the new item's state */
1417 newItem
->setDrawExpandButton(drawExpandButton
);
1418 newItem
->setDrawTree(drawTree
);
1419 newItem
->setDrawText(showText
);
1420 KTreeViewItem
* parentItem
;
1421 if (referenceItem
) {
1422 parentItem
= referenceItem
->getParent();
1423 int insertIndex
= parentItem
->childIndex(referenceItem
);
1426 parentItem
->insertChild(insertIndex
, newItem
);
1429 // no reference item, append at end of visible tree
1431 parentItem
= treeRoot
;
1432 parentItem
->appendChild(newItem
);
1435 // set item expansion
1436 if (level(newItem
) < expansion
)
1437 newItem
->setExpanded(true);
1439 // fix up branch levels of any children
1440 if (newItem
->hasChild())
1441 fixChildren(newItem
);
1443 // if repaint necessary, do it if visible and auto update
1445 if (newItem
->isVisible() || parentItem
->childCount() == 1) {
1446 bool autoU
= autoUpdate();
1447 setAutoUpdate(FALSE
);
1448 updateVisibleItems();
1449 setAutoUpdate(autoU
);
1450 if (autoU
&& isVisible())
1457 * returns pointer to item's path
1459 void KTreeView::itemPath(KTreeViewItem
* item
, KPath
& path
) const
1462 assert(item
->owner
== this);
1463 if (item
!= treeRoot
) {
1464 itemPath(item
->getParent(), path
);
1465 path
.push(item
->getText());
1470 * joins the item's branch into the tree, making the item a sibling of its
1473 void KTreeView::join(KTreeViewItem
*item
)
1475 KTreeViewItem
*itemParent
= item
->getParent();
1476 if(itemParent
->hasParent()) {
1477 bool autoU
= autoUpdate();
1478 setAutoUpdate(FALSE
);
1480 insertItem(itemParent
, item
, FALSE
);
1481 setAutoUpdate(autoU
);
1482 if(autoU
&& isVisible())
1487 // handles keyboard interface
1488 void KTreeView::keyPressEvent(QKeyEvent
* e
)
1491 return; /* nothing to do */
1493 /* if there's no current item, make the top item current */
1494 if (currentItem() < 0)
1495 setCurrentItem(topCell());
1496 assert(currentItem() >= 0); /* we need a current item */
1497 assert(itemAt(currentItem()) != 0); /* we really need a current item */
1499 // give currentItem a chance to handle the event
1500 if (itemAt(currentItem())->keyEvent(e
))
1501 return; /* handled */
1503 int pageSize
, delta
;
1504 KTreeViewItem
* item
;
1509 // make previous item current, scroll up if necessary
1510 if (currentItem() > 0) {
1511 setCurrentItem(currentItem() - 1);
1512 scrollVisible(itemAt(currentItem()), false);
1516 // make next item current, scroll down if necessary
1517 if (currentItem() < numRows() - 1) {
1518 setCurrentItem(currentItem() + 1);
1519 if (currentItem() > lastRowVisible()) {
1520 // scrollVisible is not feasible here because
1521 // it scrolls the item to the top
1522 setTopCell(topCell() + currentItem() - lastRowVisible());
1523 } else if (currentItem() < topCell()) {
1524 setTopCell(currentItem());
1529 // move highlight one page down and scroll down
1530 delta
= currentItem() - topCell();
1531 pageSize
= lastRowVisible() - topCell();
1532 setTopCell(QMIN(topCell() + pageSize
, numRows() - 1));
1533 setCurrentItem(QMIN(topCell() + delta
, numRows() - 1));
1536 // move highlight one page up and scroll up
1537 delta
= currentItem() - topCell();
1538 pageSize
= lastRowVisible() - topCell();
1539 setTopCell(QMAX(topCell() - pageSize
, 0));
1540 setCurrentItem(QMAX(topCell() + delta
, 0));
1544 // if current item has subtree and is collapsed, expand it
1545 item
= itemAt(currentItem());
1546 if (item
->isExpanded() && item
->hasChild() && key
== Key_Right
) {
1547 // going right on an expanded item is like going down
1551 expandSubTree(item
, true);
1552 scrollVisible(item
, true);
1557 // if current item has subtree and is expanded, collapse it
1558 item
= itemAt(currentItem());
1559 if ((!item
->isExpanded() || !item
->hasChild()) && key
== Key_Left
) {
1560 // going left on a collapsed item goes to its parent
1561 item
= item
->getParent();
1562 if (item
== treeRoot
)
1563 break; /* we're already at the top */
1564 assert(item
->isVisible());
1565 setCurrentItem(itemRow(item
));
1567 collapseSubTree(item
, true);
1569 scrollVisible(item
, false);
1573 // select the current item
1574 if (currentItem() >= 0)
1575 emit
selected(currentItem());
1582 // handles keyboard interface
1583 void KTreeView::keyReleaseEvent(QKeyEvent
* e
)
1585 if (currentItem() >= 0 && itemAt(currentItem()) != 0)
1586 itemAt(currentItem())->keyEvent(e
);
1589 int KTreeView::level(KTreeViewItem
* item
) const
1592 assert(item
->owner
== this);
1593 assert(item
!= treeRoot
);
1595 item
= item
->parent
->parent
; /* since item != treeRoot, there is a parent */
1597 item
= item
->parent
;
1603 /* move specified item down one slot in parent's subtree */
1604 void KTreeView::lowerItem(KTreeViewItem
*item
)
1606 KTreeViewItem
*itemParent
= item
->getParent();
1607 uint itemChildIndex
= itemParent
->childIndex(item
);
1608 if(itemChildIndex
< itemParent
->childCount() - 1) {
1609 bool autoU
= autoUpdate();
1610 setAutoUpdate(FALSE
);
1612 insertItem(itemParent
->childAt(itemChildIndex
), item
, FALSE
);
1613 setAutoUpdate(autoU
);
1614 if(autoU
&& isVisible())
1619 // handle mouse double click events by selecting the clicked item
1620 // and emitting the signal
1621 void KTreeView::mouseDoubleClickEvent(QMouseEvent
* e
)
1623 // find out which row has been clicked
1624 int itemClicked
= findRow(e
->y());
1626 if (itemClicked
< 0)
1627 return; /* invalid row, do nothing */
1629 KTreeViewItem
* item
= itemAt(itemClicked
);
1633 // translate mouse coord to cell coord
1634 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1637 if (item
->mouseEvent(e
, cellCoord
))
1641 int indent
= indentation(item
);
1642 if (item
->boundingRect(indent
).contains(cellCoord
))
1643 emit
selected(itemClicked
);
1646 // handle mouse movement events
1647 void KTreeView::mouseMoveEvent(QMouseEvent
* e
)
1649 // in rubberband_mode we actually scroll the window now
1650 if (rubberband_mode
) {
1651 move_rubberband(e
->pos());
1653 // else forward to current item
1654 int current
= currentItem();
1655 if (current
>= 0 && itemAt(current
))
1656 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1661 // handle single mouse presses
1662 void KTreeView::mousePressEvent(QMouseEvent
* e
)
1664 /* first: cancel rubberbanding if it's on */
1665 if (rubberband_mode
)
1667 // another button was pressed while rubberbanding, stop the move.
1668 // RB: if we allow other buttons while rubberbanding the tree can expand
1669 // while rubberbanding - we then need to recalculate and resize the
1670 // rubberband rect and show the new size
1675 // find out which row has been clicked
1676 int itemClicked
= findRow(e
->y());
1678 // nothing to do if not on valid row
1679 if (itemClicked
< 0)
1681 KTreeViewItem
* item
= itemAt(itemClicked
);
1685 // translate mouse coord to cell coord
1686 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1688 // give the item a crack
1689 if (item
->mouseEvent(e
, cellCoord
))
1690 return; /* event eaten by item */
1692 // check for rubberbanding
1693 if (e
->button() == MidButton
)
1695 // RB: the MMB is hardcoded to the "rubberband" scroll mode
1696 if (!rubberband_mode
) {
1697 start_rubberband(e
->pos());
1702 if (e
->button() == RightButton
) {
1703 emit
rightPressed(itemClicked
, e
->pos());
1705 /* hit test expand button (doesn't set currentItem) */
1706 else if (item
->expandButtonClicked(cellCoord
)) {
1707 if (item
->isExpanded()) {
1708 collapseSubTree(item
, true);
1710 expandSubTree(item
, true);
1711 scrollVisible(item
, true); /* make children visible */
1715 else if (item
->boundingRect(indentation(item
)).contains(cellCoord
)) {
1716 setCurrentItem(itemClicked
);
1720 // handle mouse release events
1721 void KTreeView::mouseReleaseEvent(QMouseEvent
*e
)
1723 /* if it's the MMB end rubberbanding */
1724 if (rubberband_mode
) {
1725 if (e
->button() == MidButton
)
1729 // forward to current item
1730 int current
= currentItem();
1731 if (current
>= 0 && itemAt(current
))
1732 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1735 // rubberband move: draw the rubberband
1736 void KTreeView::draw_rubberband()
1739 * RB: I'm using a white pen because of the XorROP mode. I would prefer
1740 * to draw the rectangle in red but I don't now how to get a pen which
1741 * draws red in XorROP mode (this depends on the background). In fact
1742 * the color should be configurable.
1745 if (!rubberband_mode
) return;
1746 QPainter
paint(this);
1747 paint
.setPen(white
);
1748 paint
.setRasterOp(XorROP
);
1749 paint
.drawRect(xOffset()*viewWidth()/totalWidth(),
1750 yOffset()*viewHeight()/totalHeight(),
1751 rubber_width
+1, rubber_height
+1);
1755 // rubberband move: start move
1756 void KTreeView::start_rubberband(const QPoint
& where
)
1758 if (rubberband_mode
) { // Oops!
1761 /* RB: Don't now, if this check is necessary */
1762 if (!viewWidth() || !viewHeight()) return;
1763 if (!totalWidth() || !totalHeight()) return;
1765 // calculate the size of the rubberband rectangle
1766 rubber_width
= viewWidth()*viewWidth()/totalWidth();
1767 if (rubber_width
> viewWidth()) rubber_width
= viewWidth();
1768 rubber_height
= viewHeight()*viewHeight()/totalHeight();
1769 if (rubber_height
> viewHeight()) rubber_height
= viewHeight();
1771 // remember the cursor position and the actual offset
1772 rubber_startMouse
= where
;
1773 rubber_startX
= xOffset();
1774 rubber_startY
= yOffset();
1775 rubberband_mode
=TRUE
;
1779 // rubberband move: end move
1780 void KTreeView::end_rubberband()
1782 if (!rubberband_mode
) return;
1784 rubberband_mode
= FALSE
;
1787 // rubberband move: hanlde mouse moves
1788 void KTreeView::move_rubberband(const QPoint
& where
)
1790 if (!rubberband_mode
) return;
1792 // look how much the mouse moved and calc the new scroll position
1793 QPoint delta
= where
- rubber_startMouse
;
1794 int nx
= rubber_startX
+ delta
.x() * totalWidth() / viewWidth();
1795 int ny
= rubber_startY
+ delta
.y() * totalHeight() / viewHeight();
1797 // check the new position (and make it valid)
1799 else if (nx
> maxXOffset()) nx
= maxXOffset();
1801 else if (ny
> maxYOffset()) ny
= maxYOffset();
1803 // redraw the rubberband at the new position
1810 // paints the cell at the specified row and col
1811 // col is ignored for now since there is only one
1812 void KTreeView::paintCell(QPainter
* p
, int row
, int)
1814 KTreeViewItem
* item
= itemAt(row
);
1818 QColorGroup cg
= colorGroup();
1819 int indent
= indentation(item
);
1820 item
->paint(p
, indent
, cg
,
1821 current
== row
); /* highlighted */
1825 /* This is needed to make the kcontrol's color setup working (Marcin Dalecki) */
1826 void KTreeView::paletteChange(const QPalette
&)
1828 setBackgroundColor(colorGroup().base());
1833 /* raise the specified item up one slot in parent's subtree */
1834 void KTreeView::raiseItem(KTreeViewItem
*item
)
1836 KTreeViewItem
*itemParent
= item
->getParent();
1837 int itemChildIndex
= itemParent
->childIndex(item
);
1838 if(itemChildIndex
> 0) {
1839 bool autoU
= autoUpdate();
1840 setAutoUpdate(FALSE
);
1842 insertItem(itemParent
->childAt(--itemChildIndex
), item
, TRUE
);
1843 setAutoUpdate(autoU
);
1844 if(autoU
&& isVisible())
1849 // find the item at the path
1850 KTreeViewItem
* KTreeView::recursiveFind(KPath
& path
)
1856 QString searchString
= path
.pop();
1858 // find the parent item
1859 KTreeViewItem
* parent
= recursiveFind(path
);
1864 * Iterate through the parent's children searching for searchString.
1866 KTreeViewItem
* sibling
= parent
->getChild();
1867 while (sibling
!= 0) {
1868 if (searchString
== sibling
->getText()) {
1869 break; /* found it! */
1871 sibling
= sibling
->getSibling();
1876 void KTreeView::setItemExpanded(KTreeViewItem
* item
)
1878 if (level(item
) < expansion
) {
1879 expandSubTree(item
, true);
1881 collapseSubTree(item
, true);
1885 // called by setExpandLevel for each item in tree
1886 bool KTreeView::setItemExpandLevel(KTreeViewItem
* item
, void*)
1888 assert(item
->owner
!= 0);
1889 item
->owner
->setItemExpanded(item
);
1893 // called by setExpandButtonDrawing for every item in tree
1894 // the parameter drawButton is used as (and implicitly cast to) a bool
1895 bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem
* item
,
1898 item
->setDrawExpandButton(drawButton
);
1902 // called by setShowItemText for every item in tree
1903 // the parameter newDrawText is used as (and implicitly cast to) a bool
1904 bool KTreeView::setItemShowText(KTreeViewItem
* item
,
1907 item
->setDrawText(newDrawText
);
1911 // called by setTreeDrawing for every item in tree
1912 // the parameter drawTree is used as (and implicitly cast to) a bool
1913 bool KTreeView::setItemTreeDrawing(KTreeViewItem
* item
, void* drawTree
)
1915 item
->setDrawTree(drawTree
);
1919 // makes the item a child of the item above it, splitting
1920 // the tree into a new branch
1921 void KTreeView::split(KTreeViewItem
*item
)
1923 KTreeViewItem
*itemParent
= item
->getParent();
1924 int itemChildIndex
= itemParent
->childIndex(item
);
1925 if(itemChildIndex
== 0)
1927 bool autoU
= autoUpdate();
1928 setAutoUpdate(FALSE
);
1930 appendChildItem(itemParent
->childAt(--itemChildIndex
), item
);
1931 setAutoUpdate(autoU
);
1932 if(autoU
&& isVisible())
1936 // removes the item from the tree without deleting it
1937 void KTreeView::takeItem(KTreeViewItem
* item
)
1939 assert(item
->owner
== this);
1941 // TODO: go over this function again
1943 bool wasVisible
= item
->isVisible();
1945 * If we have a current item, make sure that it is not in the subtree
1946 * that we are about to remove. If the current item is in the part
1947 * below the taken-out subtree, we must move it up a number of rows if
1948 * the taken-out subtree is at least partially visible.
1950 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1951 KTreeViewItem
* oldCurrent
= cur
;
1952 if (wasVisible
&& cur
!= 0) {
1953 KTreeViewItem
* c
= cur
;
1954 while (c
!= 0 && c
!= item
) {
1958 // move current item to parent
1959 cur
= item
->getParent();
1960 if (cur
== treeRoot
) {
1962 // move it to next or previous sibling
1963 if (moveCurrentToSibling
) {
1964 if (item
->getSibling() != 0) {
1965 cur
= item
->getSibling();
1966 } else if (treeRoot
->getChild() != item
) {
1967 cur
= treeRoot
->getChild();
1968 while (cur
!= 0 && cur
->getSibling() != item
)
1969 cur
= cur
->getSibling();
1975 KTreeViewItem
* parentItem
= item
->getParent();
1976 parentItem
->removeChild(item
);
1978 if (wasVisible
|| parentItem
->childCount() == 0) {
1979 bool autoU
= autoUpdate();
1980 setAutoUpdate(FALSE
);
1981 updateVisibleItems();
1982 setAutoUpdate(autoU
);
1983 if (autoU
&& isVisible())
1987 // re-seat the current item
1988 // row changes if cur is below the taken item
1989 current
= cur
!= 0 ? itemRow(cur
) : -1;
1990 // signal must be emitted only if item really changed
1991 if (cur
!= oldCurrent
) {
1992 updateCell(current
, 0, false);
1993 emit
highlighted(current
);
1997 // visits each item, calculates the maximum width
1998 // and updates TableView
1999 void KTreeView::updateCellWidth()
2001 // make cells at least 1 pixel wide to avoid singularities (division by zero)
2003 forEveryVisibleItem(&KTreeView::getMaxItemWidth
, &maxW
);
2004 maxItemWidth
= maxW
;
2008 int xoff
= xOffset();
2009 int yoff
= yOffset();
2010 if (xoff
> maxXOffset()) xoff
= maxXOffset();
2011 if (yoff
> maxYOffset()) yoff
= maxYOffset();
2013 setOffset(xoff
, yoff
);
2016 void KTreeView::updateVisibleItems()
2020 updateVisibleItemRec(treeRoot
, index
, count
);
2021 assert(index
== count
);
2026 void KTreeView::updateVisibleItemRec(KTreeViewItem
* item
, int& index
, int& count
)
2028 if (!item
->isExpanded()) {
2029 // no visible items if not expanded
2034 * Record the children of item in the list of visible items.
2036 * Don't register item itself, it's already in the list. Also only
2037 * allocate new space for children.
2039 count
+= item
->childCount();
2040 if (count
> itemCapacity
) {
2042 int newCapacity
= itemCapacity
;
2044 newCapacity
+= newCapacity
;
2045 } while (newCapacity
< count
);
2046 KTreeViewItem
** newItems
= new KTreeViewItem
*[newCapacity
];
2047 // clear the unneeded space
2048 for (int i
= index
; i
< newCapacity
; i
++) {
2051 // move already accumulated items over
2052 for (int i
= index
-1; i
>= 0; i
--) {
2053 newItems
[i
] = visibleItems
[i
];
2055 delete[] visibleItems
;
2056 visibleItems
= newItems
;
2057 itemCapacity
= newCapacity
;
2060 for (KTreeViewItem
* i
= item
->getChild(); i
!= 0; i
= i
->getSibling()) {
2061 visibleItems
[index
++] = i
;
2062 updateVisibleItemRec(i
, index
, count
);