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
,
342 bool hasFocus
, GUIStyle style
) const
345 if (style
== WindowsStyle
)
346 fc
= darkBlue
; /* hardcoded in Qt */
348 fc
= colorGroup
.text();
349 QRect textRect
= textBoundingRect(indent
);
351 textRect
.coords(&l
, &t
, &r
, &b
);
353 outerRect
.setCoords(l
- 2, t
- 2, r
+ 2, b
+ 2);
354 if (style
== WindowsStyle
) { /* Windows style highlight */
356 p
->fillRect(textRect
, fc
); /* highlight background */
357 textRect
.setCoords(l
- 1, t
- 1, r
+ 1, b
+ 1);
358 p
->setPen(QPen(yellow
, 0, DotLine
));
359 p
->setBackgroundColor(fc
);
360 p
->setBackgroundMode(OpaqueMode
);
361 p
->drawRect(textRect
);
363 p
->drawRect(outerRect
);
365 p
->fillRect(outerRect
, fc
); /* highlight background */
367 } else { /* Motif style highlight */
369 p
->fillRect(textRect
, fc
); /* highlight background */
371 p
->drawRect(outerRect
);
373 p
->fillRect(outerRect
, fc
); /* highlight background */
378 // draw the text, highlighted if requested
379 void KTreeViewItem::paintText(QPainter
* p
, int indent
, int cellHeight
,
380 const QColorGroup
& cg
, bool highlighted
) const
382 int textX
= indent
+ pixmap
.width() + 3;
383 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
384 p
->fontMetrics().ascent();
387 paintHighlight(p
, indent
, cg
,
388 owner
->hasFocus(), owner
->style());
389 p
->setPen(cg
.base());
390 p
->setBackgroundColor(cg
.text());
393 p
->setPen(cg
.text());
394 p
->setBackgroundColor(cg
.base());
396 p
->drawText(textX
, textY
, text
);
399 // paint the tree structure
400 void KTreeViewItem::paintTree(QPainter
* p
, int indent
, int cellHeight
,
401 const QColorGroup
& cg
) const
403 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
404 int cellCenterY
= cellHeight
/ 2;
405 int cellBottomY
= cellHeight
- 1;
406 int itemLeaderX
= indent
- 1;
408 p
->setPen(cg
.background());
411 * If this is not the first item in the tree draw the line up
412 * towards parent or sibling.
414 if (parent
->parent
!= 0 || parent
->getChild() != this)
415 p
->drawLine(parentLeaderX
, 0, parentLeaderX
, cellCenterY
);
417 // draw the line down towards sibling
419 p
->drawLine(parentLeaderX
, cellCenterY
, parentLeaderX
, cellBottomY
);
422 * If this item has children or siblings in the tree or is a child of
423 * an item other than the root item then draw the little line from the
424 * item out to the left.
426 if (sibling
|| (doExpandButton
&& (child
|| delayedExpanding
)) ||
427 parent
->parent
!= 0 ||
429 * The following handles the case of an item at the end of the
430 * topmost level which doesn't have children.
432 parent
->getChild() != this)
434 p
->drawLine(parentLeaderX
, cellCenterY
, itemLeaderX
, cellCenterY
);
438 * If there are siblings of ancestors below, draw our portion of the
439 * branches that extend through this cell.
441 KTreeViewItem
* prevRoot
= parent
;
442 while (prevRoot
->getParent() != 0) { /* while not root item */
443 assert(prevRoot
->owner
== owner
);
444 if (prevRoot
->hasSibling()) {
445 int sibLeaderX
= owner
->indentation(prevRoot
) - (owner
->itemIndent
/ 2);
446 p
->drawLine(sibLeaderX
, 0, sibLeaderX
, cellBottomY
);
448 prevRoot
= prevRoot
->getParent();
452 // removes the given (direct) child from the branch
453 bool KTreeViewItem::removeChild(KTreeViewItem
* theChild
)
455 // search item in list of children
456 KTreeViewItem
* prevItem
= 0;
457 KTreeViewItem
* toRemove
= getChild();
458 while (toRemove
&& toRemove
!= theChild
) {
460 toRemove
= toRemove
->getSibling();
466 child
= toRemove
->getSibling();
468 prevItem
->sibling
= toRemove
->getSibling();
471 toRemove
->setOwner(0);
473 assert((numChildren
== 0) == (child
== 0));
475 return toRemove
!= 0;
478 // sets the delayed-expanding flag
479 void KTreeViewItem::setDelayedExpanding(bool flag
)
481 delayedExpanding
= flag
;
484 // tells the item whether it shall delete child items
485 void KTreeViewItem::setDeleteChildren(bool flag
)
487 deleteChildren
= flag
;
490 // sets the draw expand button flag of this item
491 void KTreeViewItem::setDrawExpandButton(bool doit
)
493 doExpandButton
= doit
;
496 // sets the draw text flag of this item
497 void KTreeViewItem::setDrawText(bool doit
)
502 // sets the draw tree branch flag of this item
503 void KTreeViewItem::setDrawTree(bool doit
)
508 // sets the expanded flag of this item
509 void KTreeViewItem::setExpanded(bool is
)
514 // sets the owner of this item and its children siblings
515 void KTreeViewItem::setOwner(KTreeView
* newOwner
, bool includeSiblings
)
517 /* Note: set owner of children's siblings! */
520 getChild()->setOwner(newOwner
, true);
521 if (includeSiblings
&& getSibling())
522 getSibling()->setOwner(newOwner
, true);
525 // sets the item pixmap to the given pixmap
526 void KTreeViewItem::setPixmap(const QPixmap
& pm
)
531 // sets the item text to the given string
532 void KTreeViewItem::setText(const QString
& t
)
537 // counts the child items and stores the result in numChildren
538 void KTreeViewItem::synchNumChildren()
541 KTreeViewItem
* item
= getChild();
544 item
= item
->getSibling();
549 * returns the bounding rect of the item text in cell coordinates couldn't
550 * get QFontMetrics::boundingRect() to work right so I made my own
552 QRect
KTreeViewItem::textBoundingRect(int indent
) const
554 const QFontMetrics
& fm
= owner
->fontMetrics();
555 int cellHeight
= height(fm
);
556 int rectX
= indent
+ pixmap
.width() + 2;
557 int rectY
= (cellHeight
- fm
.height()) / 2;
558 int rectW
= fm
.width(text
) + 2;
559 int rectH
= fm
.height();
560 return QRect(rectX
, rectY
, rectW
, rectH
);
563 // returns the total width of text and pixmap, including margins, spacing
564 // and indent, or -1 if empty -- SHOULD NEVER BE -1!
565 int KTreeViewItem::width(int indent
) const
567 return width(indent
, owner
->fontMetrics());
570 // The width of an item is composed of the following:
571 // - indentation (indent with times level)
573 // - 2 pixels for highlight border
577 // - 2 pixels for highlight border
578 int KTreeViewItem::width(int indent
, const QFontMetrics
& fm
) const
580 return indent
+ pixmap
.width() + fm
.width(text
) + 6;
585 * -------------------------------------------------------------------
589 * -------------------------------------------------------------------
593 KTreeView::KTreeView(QWidget
*parent
,
596 QTableView(parent
, name
, f
),
599 drawExpandButton(true),
607 rubberband_mode(false)
614 setTableFlags(Tbl_autoScrollBars
| Tbl_clipCellPainting
| Tbl_snapToVGrid
);
615 clearTableFlags(Tbl_scrollLastVCell
| Tbl_scrollLastHCell
| Tbl_snapToVGrid
);
619 setFrameStyle(QFrame::WinPanel
| QFrame::Sunken
);
620 setBackgroundColor(colorGroup().base());
623 setFrameStyle(QFrame::Panel
| QFrame::Plain
);
626 setFocusPolicy(StrongFocus
);
627 treeRoot
= new KTreeViewItem
;
628 treeRoot
->setExpanded(true);
629 treeRoot
->owner
= this;
631 visibleItems
= new KTreeViewItem
*[itemCapacity
];
632 // clear those pointers
633 for (int j
= itemCapacity
-1; j
>= 0; j
--) {
639 KTreeView::~KTreeView()
643 delete[] visibleItems
;
647 // appends a child to the item at the given index with the given text
649 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
652 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
653 item
->setDeleteChildren(true);
654 appendChildItem(item
, index
);
657 // appends a child to the item at the end of the given path with
658 // the given text and pixmap
659 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
660 const KPath
& thePath
)
662 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
663 item
->setDeleteChildren(true);
664 appendChildItem(item
, thePath
);
667 // appends the given item to the children of the item at the given index
668 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, int index
)
670 /* find parent item and append new item to parent's sub tree */
671 KTreeViewItem
* parentItem
= itemAt(index
);
674 appendChildItem(parentItem
, newItem
);
677 // appends the given item to the children of the item at the end of the
679 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, const KPath
& thePath
)
681 /* find parent item and append new item to parent's sub tree */
682 KTreeViewItem
* parentItem
= itemAt(thePath
);
685 appendChildItem(parentItem
, newItem
);
688 // indicates whether horizontal scrollbar appears only when needed
689 bool KTreeView::autoBottomScrollBar() const
691 return testTableFlags(Tbl_autoHScrollBar
);
694 // indicates whether vertical scrollbar appears only when needed
695 bool KTreeView::autoScrollBar() const
697 return testTableFlags(Tbl_autoVScrollBar
);
700 // indicates whether display updates automatically on changes
701 bool KTreeView::autoUpdate() const
703 return QTableView::autoUpdate();
706 // indicates whether horizontal scrollbar is present
707 bool KTreeView::bottomScrollBar() const
709 return testTableFlags(Tbl_hScrollBar
);
712 // translate mouse coord to cell coord
713 QPoint
KTreeView::cellCoords(int row
, const QPoint
& widgetCoord
)
715 int cellX
= 0, cellY
= 0;
717 rowYPos(row
, &cellY
);
718 return QPoint(widgetCoord
.x() - cellX
, widgetCoord
.y() - cellY
);
721 // find item at specified index and change pixmap and/or text
722 void KTreeView::changeItem(const char *newText
,
723 const QPixmap
*newPixmap
,
726 KTreeViewItem
*item
= itemAt(index
);
728 changeItem(item
, index
, newText
, newPixmap
);
731 // find item at end of specified path, and change pixmap and/or text
732 void KTreeView::changeItem(const char* newText
,
733 const QPixmap
* newPixmap
,
734 const KPath
& thePath
)
736 KTreeViewItem
* item
= itemAt(thePath
);
738 int index
= itemRow(item
);
739 changeItem(item
, index
, newText
, newPixmap
);
743 // clear all items from list and erase display
744 void KTreeView::clear()
748 /* somewhat of a hack for takeItem so it doesn't update the current item... */
751 bool autoU
= autoUpdate();
752 setAutoUpdate(FALSE
);
753 QStack
<KTreeViewItem
> stack
;
754 stack
.push(treeRoot
);
755 while(!stack
.isEmpty()) {
756 KTreeViewItem
*item
= stack
.pop();
757 if(item
->hasChild()) {
759 stack
.push(item
->getChild());
761 else if(item
->hasSibling()) {
763 stack
.push(item
->getSibling());
765 else if(item
->getParent() != 0) {
771 if(goingDown
|| QApplication::closingDown())
773 setAutoUpdate(autoU
);
774 if(autoU
&& isVisible())
778 // return a count of all the items in the tree, whether visible or not
779 uint
KTreeView::count()
782 forEveryItem(&KTreeView::countItem
, (void *)&total
);
786 // returns the index of the current (highlighted) item
787 int KTreeView::currentItem() const
792 // collapses the item at the specified row index.
793 void KTreeView::collapseItem(int index
, bool emitSignal
)
795 KTreeViewItem
* item
= itemAt(index
);
797 collapseSubTree(item
, emitSignal
);
800 // expands the item at the specified row indes.
801 void KTreeView::expandItem(int index
, bool emitSignal
)
803 KTreeViewItem
* item
= itemAt(index
);
805 expandSubTree(item
, emitSignal
);
808 // returns the depth the tree is automatically expanded to when
810 int KTreeView::expandLevel() const
815 // visits every item in the tree, visible or not and applies
816 // the user supplied function with the item and user data passed as parameters
817 // if user supplied function returns true, traversal ends and function returns
818 bool KTreeView::forEveryItem(KForEveryFunc func
, void* user
, KTreeViewItem
* item
)
823 assert(item
->owner
== this);
824 item
= item
->getChild();
827 // visit the siblings
828 if ((*func
)(item
, user
)) {
831 // visit the children (recursively)
832 if (item
->hasChild()) {
833 if (forEveryItem(func
, user
, item
))
836 item
= item
->getSibling();
841 // visits every visible item in the tree in order and applies the
842 // user supplied function with the item and user data passed as parameters
843 // if user supplied function returns TRUE, traversal ends and function
845 bool KTreeView::forEveryVisibleItem(KForEveryFunc func
, void *user
,
851 // children are invisible (hence, nothing to do)
852 // if item is invisible or collapsed
853 if (!item
->isVisible() || !item
->isExpanded()) {
857 assert(item
->owner
== this);
858 item
= item
->getChild();
861 // visit the siblings
862 if ((*func
)(item
, user
)) {
865 // visit the children (recursively)
866 if (item
->hasChild() && item
->isExpanded()) {
867 if (forEveryVisibleItem(func
, user
, item
))
870 item
= item
->getSibling();
875 // returns a pointer to the KTreeViewItem at the current index
876 // or 0 if no current item
877 KTreeViewItem
*KTreeView::getCurrentItem()
879 if(current
== -1) return 0;
880 return itemAt(current
);
883 // returns the current indent spacing
884 int KTreeView::indentSpacing()
889 // inserts a new item with the specified text and pixmap before
890 // or after the item at the given index, depending on the value
892 // if index is negative, appends item to tree at root level
893 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
894 int row
, bool prefix
)
896 KTreeViewItem
* refItem
= itemAt(row
);
898 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
899 item
->setDeleteChildren(true);
901 bool success
= insertItem(refItem
, item
, prefix
);
907 // inserts a new item with the specified text and pixmap before
908 // or after the item at the end of the given path, depending on the value
910 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
911 const KPath
& path
, bool prefix
)
913 KTreeViewItem
* refItem
= itemAt(path
);
915 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
916 item
->setDeleteChildren(true);
918 bool success
= insertItem(refItem
, item
, prefix
);
924 // inserts the given item or derived object into the tree before
925 // or after the item at the given index, depending on the value
927 // if index is negative, appends item to tree at root level
928 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
929 int index
, bool prefix
)
931 // find the item currently at the index, if there is one
932 KTreeViewItem
* refItem
= itemAt(index
);
934 // insert new item at the appropriate place
935 return insertItem(refItem
, newItem
, prefix
);
938 // inserts the given item or derived object into the tree before
939 // or after the item at the end of the given path, depending on the value
941 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
942 const KPath
& thePath
, bool prefix
)
944 // find the item currently at the end of the path, if there is one
945 KTreeViewItem
* refItem
= itemAt(thePath
);
947 // insert new item at appropriate place
948 return insertItem(refItem
, newItem
, prefix
);
952 * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
955 KTreeViewItem
* KTreeView::itemAt(int row
)
957 if (row
< 0 || row
>= numRows()) {
961 // lookup the item in the list of visible items
962 assert(row
< itemCapacity
);
963 KTreeViewItem
* i
= visibleItems
[row
];
969 // returns pointer to KTreeViewItem at the end of the
970 // path or 0 if not found
971 KTreeViewItem
* KTreeView::itemAt(const KPath
& path
)
976 // need a copy of the path because recursiveFind will destroy it
978 pathCopy
.setAutoDelete(false);
981 return recursiveFind(pathCopy
);
984 // computes the path of the item at the specified index
985 // if index is invalid, nothing is done.
986 void KTreeView::itemPath(int row
, KPath
& path
)
988 KTreeViewItem
* item
= itemAt(row
);
990 itemPath(item
, path
);
994 // returns the row in the visible tree of the given item or
996 int KTreeView::itemRow(KTreeViewItem
* item
)
998 if (item
->owner
== this) {
999 // search in list of visible items
1000 for (int i
= numRows()-1; i
>= 0; i
--) {
1001 if (visibleItems
[i
] == item
) {
1011 * move the subtree at the specified index up one branch level (make root
1012 * item a sibling of its current parent)
1014 void KTreeView::join(int index
)
1016 KTreeViewItem
*item
= itemAt(index
);
1022 * move the subtree at the specified index up one branch level (make root
1023 * item a sibling of it's current parent)
1025 void KTreeView::join(const KPath
& path
)
1027 KTreeViewItem
*item
= itemAt(path
);
1032 /* move item at specified index one slot down in its parent's sub tree */
1033 void KTreeView::lowerItem(int index
)
1035 KTreeViewItem
*item
= itemAt(index
);
1040 /* move item at specified path one slot down in its parent's sub tree */
1041 void KTreeView::lowerItem(const KPath
& path
)
1043 KTreeViewItem
* item
= itemAt(path
);
1048 /* move item at specified index one slot up in its parent's sub tree */
1049 void KTreeView::raiseItem(int index
)
1051 KTreeViewItem
* item
= itemAt(index
);
1056 /* move item at specified path one slot up in its parent's sub tree */
1057 void KTreeView::raiseItem(const KPath
& path
)
1059 KTreeViewItem
* item
= itemAt(path
);
1064 // remove the item at the specified index and delete it
1065 void KTreeView::removeItem(int index
)
1067 KTreeViewItem
*item
= itemAt(index
);
1074 // remove the item at the end of the specified path and delete it
1075 void KTreeView::removeItem(const KPath
& thePath
)
1077 KTreeViewItem
* item
= itemAt(thePath
);
1084 // indicates whether vertical scrollbar is present
1085 bool KTreeView::scrollBar() const
1087 return testTableFlags(Tbl_vScrollBar
);
1090 void KTreeView::scrollVisible(KTreeViewItem
* item
, bool children
)
1094 int row
= itemRow(item
);
1096 return; /* do nothing if invisible */
1098 if (children
&& item
->isExpanded()) {
1099 // we are concerned about children
1100 if (!rowIsVisible(row
)) {
1101 // just move to the top
1104 // this is the complicated part
1105 // count the visible children (including grandchildren)
1107 forEveryVisibleItem(countItem
, &numVisible
, item
);
1108 // if the last child is visible, do nothing
1109 if (rowIsVisible(row
+ numVisible
))
1112 * Basically, item will become the top cell; but if there are
1113 * more visible rows in the widget than we have children, then
1114 * we don't move that far.
1116 int remain
= lastRowVisible()-topCell()-numVisible
;
1120 setTopCell(QMAX(0,row
-remain
));
1124 // we are not concerned about children
1125 if (rowIsVisible(row
))
1127 // just move the item to the top
1132 // enables/disables auto update of display
1133 void KTreeView::setAutoUpdate(bool enable
)
1135 QTableView::setAutoUpdate(enable
);
1138 // enables/disables horizontal scrollbar
1139 void KTreeView::setBottomScrollBar(bool enable
)
1141 enable
? setTableFlags(Tbl_hScrollBar
) :
1142 clearTableFlags(Tbl_hScrollBar
);
1145 // sets the current item and hightlights it, emitting signals
1146 void KTreeView::setCurrentItem(int row
)
1150 int numVisible
= numRows();
1151 if (row
> numVisible
)
1153 int oldCurrent
= current
;
1155 if (oldCurrent
< numVisible
)
1156 updateCell(oldCurrent
, 0);
1158 updateCell(current
, 0, false);
1159 emit
highlighted(current
);
1163 // enables/disables drawing of expand button
1164 void KTreeView::setExpandButtonDrawing(bool enable
)
1166 if (drawExpandButton
== enable
)
1168 drawExpandButton
= enable
;
1170 // the user parameter is cast to a bool in setItemExpandButtonDrawing
1171 forEveryItem(&KTreeView::setItemExpandButtonDrawing
, enable
? &enable
: 0);
1173 if (autoUpdate() && isVisible())
1177 // sets depth to which subtrees are automatically expanded, and
1178 // redraws tree if auto update enabled
1179 void KTreeView::setExpandLevel(int level
)
1181 if (expansion
== level
)
1184 KTreeViewItem
* item
= getCurrentItem();
1185 forEveryItem(&KTreeView::setItemExpandLevel
, 0);
1187 if (item
->getParent()->isExpanded())
1189 item
= item
->getParent();
1192 setCurrentItem(itemRow(item
));
1193 if (autoUpdate() && isVisible())
1197 // sets the indent margin for all branches and repaints if auto update enabled
1198 void KTreeView::setIndentSpacing(int spacing
)
1200 if (itemIndent
== spacing
)
1202 itemIndent
= spacing
;
1204 if (autoUpdate() && isVisible())
1208 // enables/disables vertical scrollbar
1209 void KTreeView::setScrollBar(bool enable
)
1211 enable
? setTableFlags(Tbl_vScrollBar
) :
1212 clearTableFlags(Tbl_vScrollBar
);
1215 // enables/disables display of item text (keys)
1216 void KTreeView::setShowItemText(bool enable
)
1218 if (showText
== enable
)
1222 // the user parameter is cast to a bool in setItemShowText
1223 forEveryItem(&KTreeView::setItemShowText
, enable
? &enable
: 0);
1225 if (autoUpdate() && isVisible())
1229 // indicates whether vertical scrolling is by pixel or row
1230 void KTreeView::setSmoothScrolling(bool enable
)
1232 enable
? setTableFlags(Tbl_smoothVScrolling
) :
1233 clearTableFlags(Tbl_smoothVScrolling
);
1236 // enables/disables tree branch drawing
1237 void KTreeView::setTreeDrawing(bool enable
)
1239 if (drawTree
== enable
)
1243 // the user parameter is cast to a bool in setItemTreeDrawing
1244 forEveryItem(&KTreeView::setItemTreeDrawing
, enable
? &enable
: 0);
1246 if (autoUpdate() && isVisible())
1250 // indicates whether item text keys are displayed
1251 bool KTreeView::showItemText() const
1256 // indicates whether scrolling is by pixel or row
1257 bool KTreeView::smoothScrolling() const
1259 return testTableFlags(Tbl_smoothVScrolling
);
1262 // indents the item at the given index, splitting the tree into
1264 void KTreeView::split(int index
)
1266 KTreeViewItem
*item
= itemAt(index
);
1271 // indents the item at the given path, splitting the tree into
1273 void KTreeView::split(const KPath
& path
)
1275 KTreeViewItem
* item
= itemAt(path
);
1280 // removes item at specified index from tree but does not delete it
1281 // returns pointer to the item or 0 if not succesful
1282 KTreeViewItem
*KTreeView::takeItem(int index
)
1284 KTreeViewItem
*item
= itemAt(index
);
1290 // removes item at specified path from tree but does not delete it
1291 // returns pointer to the item or 0 if not successful
1292 KTreeViewItem
* KTreeView::takeItem(const KPath
& path
)
1294 KTreeViewItem
* item
= itemAt(path
);
1300 // indicates whether tree branches are drawn
1301 bool KTreeView::treeDrawing() const
1307 // appends a child to the specified parent item (note: a child, not a sibling, is added!)
1308 void KTreeView::appendChildItem(KTreeViewItem
* theParent
,
1309 KTreeViewItem
* newItem
)
1311 theParent
->appendChild(newItem
);
1314 newItem
->setDrawExpandButton(drawExpandButton
);
1315 newItem
->setDrawTree(drawTree
);
1316 newItem
->setDrawText(showText
);
1317 if (level(newItem
) < expansion
) {
1318 newItem
->setExpanded(true);
1321 // fix up branch levels of any children that the new item may already have
1322 if(newItem
->hasChild()) {
1323 fixChildren(newItem
);
1326 // if necessary, adjust cell width, number of rows and repaint
1327 if (newItem
->isVisible() || theParent
->childCount() == 1) {
1328 bool autoU
= autoUpdate();
1329 setAutoUpdate(false);
1330 updateVisibleItems();
1331 setAutoUpdate(autoU
);
1332 if (autoU
&& isVisible())
1337 // returns the height of the cell(row) at the specified row (index)
1338 int KTreeView::cellHeight(int row
)
1340 return itemAt(row
)->height(fontMetrics());
1343 // returns the width of the cells. Note: this is mostly for derived classes
1344 // which have more than 1 column
1345 int KTreeView::cellWidth(int /*col*/)
1347 return maxItemWidth
;
1350 // changes the given item with the new text and/or pixmap
1351 void KTreeView::changeItem(KTreeViewItem
* toChange
, int itemRow
,
1352 const char* newText
, const QPixmap
* newPixmap
)
1354 int indent
= indentation(toChange
);
1355 int oldWidth
= toChange
->width(indent
);
1357 toChange
->setText(newText
);
1359 toChange
->setPixmap(*newPixmap
);
1360 if(oldWidth
!= toChange
->width(indent
))
1364 if(autoUpdate() && rowIsVisible(itemRow
))
1365 updateCell(itemRow
, 0);
1368 // collapses the subtree at the specified item
1369 void KTreeView::collapseSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1371 assert(subRoot
->owner
== this);
1372 if (!subRoot
->isExpanded())
1375 // must move the current item if it is visible
1376 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1378 subRoot
->setExpanded(false);
1379 if (subRoot
->isVisible()) {
1380 bool autoU
= autoUpdate();
1381 setAutoUpdate(false);
1382 updateVisibleItems();
1383 // re-seat current item
1385 setCurrentItem(itemRow(cur
));
1388 emit
collapsed(itemRow(subRoot
));
1390 setAutoUpdate(autoU
);
1391 if (autoU
&& isVisible())
1396 // used by count() with forEach() function to count total number
1397 // of items in the tree
1398 bool KTreeView::countItem(KTreeViewItem
*, void* total
)
1400 int* t
= static_cast<int*>(total
);
1405 // expands the subtree at the given item
1406 void KTreeView::expandSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1408 assert(subRoot
->owner
== this);
1409 if (subRoot
->isExpanded())
1412 // must move the current item if it is visible
1413 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1417 if (subRoot
->delayedExpanding
) {
1418 emit
expanding(subRoot
, allow
);
1423 subRoot
->setExpanded(true);
1425 if (subRoot
->isVisible()) {
1426 bool autoU
= autoUpdate();
1427 setAutoUpdate(false);
1428 updateVisibleItems();
1429 // re-seat current item
1431 setCurrentItem(itemRow(cur
));
1434 emit
expanded(itemRow(subRoot
));
1436 setAutoUpdate(autoU
);
1437 if (autoU
&& isVisible())
1442 // fix up branch levels out of whack from split/join operations on the tree
1443 void KTreeView::fixChildren(KTreeViewItem
*parentItem
)
1445 KTreeViewItem
* childItem
= 0;
1446 KTreeViewItem
* siblingItem
= 0;
1447 // int childBranch = parentItem->getBranch() + 1;
1448 if(parentItem
->hasChild()) {
1449 childItem
= parentItem
->getChild();
1450 // childItem->setBranch(childBranch);
1451 childItem
->owner
= parentItem
->owner
;
1452 fixChildren(childItem
);
1454 while(childItem
&& childItem
->hasSibling()) {
1455 siblingItem
= childItem
->getSibling();
1456 // siblingItem->setBranch(childBranch);
1457 siblingItem
->owner
= parentItem
->owner
;
1458 fixChildren(siblingItem
);
1459 childItem
= siblingItem
;
1464 * Handle QFocusEvent processing by setting current item to top row if
1465 * there is no current item, and updates cell to add or delete the focus
1466 * rectangle on the highlight bar. The base class is not called because it
1467 * does a repaint() which causes flicker.
1469 void KTreeView::focusInEvent(QFocusEvent
*)
1471 if (current
< 0 && numRows() > 0)
1472 setCurrentItem(topCell());
1473 updateCell(current
, 0);
1476 void KTreeView::focusOutEvent(QFocusEvent
*)
1478 updateCell(current
, 0);
1481 // called by updateCellWidth() for each item in the visible list
1482 bool KTreeView::getMaxItemWidth(KTreeViewItem
* item
, void* user
)
1484 assert(item
->owner
!= 0);
1485 int indent
= item
->owner
->indentation(item
);
1486 int* maxW
= static_cast<int*>(user
);
1487 int w
= item
->width(indent
);
1493 int KTreeView::indentation(KTreeViewItem
* item
) const
1495 return level(item
) * itemIndent
+ itemIndent
+ 3;
1498 // inserts the new item before or after the reference item, depending
1499 // on the value of prefix
1500 bool KTreeView::insertItem(KTreeViewItem
* referenceItem
,
1501 KTreeViewItem
* newItem
,
1504 assert(newItem
!= 0);
1505 assert(referenceItem
== 0 || referenceItem
->owner
== this);
1507 /* set the new item's state */
1508 newItem
->setDrawExpandButton(drawExpandButton
);
1509 newItem
->setDrawTree(drawTree
);
1510 newItem
->setDrawText(showText
);
1511 KTreeViewItem
* parentItem
;
1512 if (referenceItem
) {
1513 parentItem
= referenceItem
->getParent();
1514 int insertIndex
= parentItem
->childIndex(referenceItem
);
1517 parentItem
->insertChild(insertIndex
, newItem
);
1520 // no reference item, append at end of visible tree
1522 parentItem
= treeRoot
;
1523 parentItem
->appendChild(newItem
);
1526 // set item expansion
1527 if (level(newItem
) < expansion
)
1528 newItem
->setExpanded(true);
1530 // fix up branch levels of any children
1531 if (newItem
->hasChild())
1532 fixChildren(newItem
);
1534 // if repaint necessary, do it if visible and auto update
1536 if (newItem
->isVisible() || parentItem
->childCount() == 1) {
1537 bool autoU
= autoUpdate();
1538 setAutoUpdate(FALSE
);
1539 updateVisibleItems();
1540 setAutoUpdate(autoU
);
1541 if (autoU
&& isVisible())
1548 * returns pointer to item's path
1550 void KTreeView::itemPath(KTreeViewItem
* item
, KPath
& path
) const
1553 assert(item
->owner
== this);
1554 if (item
!= treeRoot
) {
1555 itemPath(item
->getParent(), path
);
1556 path
.push(new QString(item
->getText()));
1561 * joins the item's branch into the tree, making the item a sibling of its
1564 void KTreeView::join(KTreeViewItem
*item
)
1566 KTreeViewItem
*itemParent
= item
->getParent();
1567 if(itemParent
->hasParent()) {
1568 bool autoU
= autoUpdate();
1569 setAutoUpdate(FALSE
);
1571 insertItem(itemParent
, item
, FALSE
);
1572 setAutoUpdate(autoU
);
1573 if(autoU
&& isVisible())
1578 // handles keyboard interface
1579 void KTreeView::keyPressEvent(QKeyEvent
* e
)
1582 return; /* nothing to do */
1584 /* if there's no current item, make the top item current */
1585 if (currentItem() < 0)
1586 setCurrentItem(topCell());
1587 assert(currentItem() >= 0); /* we need a current item */
1588 assert(itemAt(currentItem()) != 0); /* we really need a current item */
1590 // give currentItem a chance to handle the event
1591 if (itemAt(currentItem())->keyEvent(e
))
1592 return; /* handled */
1594 int pageSize
, delta
;
1595 KTreeViewItem
* item
;
1600 // make previous item current, scroll up if necessary
1601 if (currentItem() > 0) {
1602 setCurrentItem(currentItem() - 1);
1603 scrollVisible(itemAt(currentItem()), false);
1607 // make next item current, scroll down if necessary
1608 if (currentItem() < numRows() - 1) {
1609 setCurrentItem(currentItem() + 1);
1610 if (currentItem() > lastRowVisible()) {
1611 // scrollVisible is not feasible here because
1612 // it scrolls the item to the top
1613 setTopCell(topCell() + currentItem() - lastRowVisible());
1614 } else if (currentItem() < topCell()) {
1615 setTopCell(currentItem());
1620 // move highlight one page down and scroll down
1621 delta
= currentItem() - topCell();
1622 pageSize
= lastRowVisible() - topCell();
1623 setTopCell(QMIN(topCell() + pageSize
, numRows() - 1));
1624 setCurrentItem(QMIN(topCell() + delta
, numRows() - 1));
1627 // move highlight one page up and scroll up
1628 delta
= currentItem() - topCell();
1629 pageSize
= lastRowVisible() - topCell();
1630 setTopCell(QMAX(topCell() - pageSize
, 0));
1631 setCurrentItem(QMAX(topCell() + delta
, 0));
1635 // if current item has subtree and is collapsed, expand it
1636 item
= itemAt(currentItem());
1637 if (item
->isExpanded() && item
->hasChild() && key
== Key_Right
) {
1638 // going right on an expanded item is like going down
1642 expandSubTree(item
, true);
1643 scrollVisible(item
, true);
1648 // if current item has subtree and is expanded, collapse it
1649 item
= itemAt(currentItem());
1650 if ((!item
->isExpanded() || !item
->hasChild()) && key
== Key_Left
) {
1651 // going left on a collapsed item goes to its parent
1652 item
= item
->getParent();
1653 if (item
== treeRoot
)
1654 break; /* we're already at the top */
1655 assert(item
->isVisible());
1656 setCurrentItem(itemRow(item
));
1658 collapseSubTree(item
, true);
1660 scrollVisible(item
, false);
1664 // select the current item
1665 if (currentItem() >= 0)
1666 emit
selected(currentItem());
1673 // handles keyboard interface
1674 void KTreeView::keyReleaseEvent(QKeyEvent
* e
)
1676 if (currentItem() >= 0 && itemAt(currentItem()) != 0)
1677 itemAt(currentItem())->keyEvent(e
);
1680 int KTreeView::level(KTreeViewItem
* item
) const
1683 assert(item
->owner
== this);
1684 assert(item
!= treeRoot
);
1686 item
= item
->parent
->parent
; /* since item != treeRoot, there is a parent */
1688 item
= item
->parent
;
1694 /* move specified item down one slot in parent's subtree */
1695 void KTreeView::lowerItem(KTreeViewItem
*item
)
1697 KTreeViewItem
*itemParent
= item
->getParent();
1698 uint itemChildIndex
= itemParent
->childIndex(item
);
1699 if(itemChildIndex
< itemParent
->childCount() - 1) {
1700 bool autoU
= autoUpdate();
1701 setAutoUpdate(FALSE
);
1703 insertItem(itemParent
->childAt(itemChildIndex
), item
, FALSE
);
1704 setAutoUpdate(autoU
);
1705 if(autoU
&& isVisible())
1710 // handle mouse double click events by selecting the clicked item
1711 // and emitting the signal
1712 void KTreeView::mouseDoubleClickEvent(QMouseEvent
* e
)
1714 // find out which row has been clicked
1715 int itemClicked
= findRow(e
->y());
1717 if (itemClicked
< 0)
1718 return; /* invalid row, do nothing */
1720 KTreeViewItem
* item
= itemAt(itemClicked
);
1724 // translate mouse coord to cell coord
1725 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1728 if (item
->mouseEvent(e
, cellCoord
))
1732 int indent
= indentation(item
);
1733 if (item
->boundingRect(indent
).contains(cellCoord
))
1734 emit
selected(itemClicked
);
1737 // handle mouse movement events
1738 void KTreeView::mouseMoveEvent(QMouseEvent
* e
)
1740 // in rubberband_mode we actually scroll the window now
1741 if (rubberband_mode
) {
1742 move_rubberband(e
->pos());
1744 // else forward to current item
1745 int current
= currentItem();
1746 if (current
>= 0 && itemAt(current
))
1747 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1752 // handle single mouse presses
1753 void KTreeView::mousePressEvent(QMouseEvent
* e
)
1755 /* first: cancel rubberbanding if it's on */
1756 if (rubberband_mode
)
1758 // another button was pressed while rubberbanding, stop the move.
1759 // RB: if we allow other buttons while rubberbanding the tree can expand
1760 // while rubberbanding - we then need to recalculate and resize the
1761 // rubberband rect and show the new size
1766 // find out which row has been clicked
1767 int itemClicked
= findRow(e
->y());
1769 // nothing to do if not on valid row
1770 if (itemClicked
< 0)
1772 KTreeViewItem
* item
= itemAt(itemClicked
);
1776 // translate mouse coord to cell coord
1777 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1779 // give the item a crack
1780 if (item
->mouseEvent(e
, cellCoord
))
1781 return; /* event eaten by item */
1783 // check for rubberbanding
1784 if (e
->button() == MidButton
)
1786 // RB: the MMB is hardcoded to the "rubberband" scroll mode
1787 if (!rubberband_mode
) {
1788 start_rubberband(e
->pos());
1793 if (e
->button() == RightButton
) {
1794 emit
rightPressed(itemClicked
, e
->pos());
1796 /* hit test expand button (doesn't set currentItem) */
1797 else if (item
->expandButtonClicked(cellCoord
)) {
1798 if (item
->isExpanded()) {
1799 collapseSubTree(item
, true);
1801 expandSubTree(item
, true);
1802 scrollVisible(item
, true); /* make children visible */
1806 else if (item
->boundingRect(indentation(item
)).contains(cellCoord
)) {
1807 setCurrentItem(itemClicked
);
1811 // handle mouse release events
1812 void KTreeView::mouseReleaseEvent(QMouseEvent
*e
)
1814 /* if it's the MMB end rubberbanding */
1815 if (rubberband_mode
) {
1816 if (e
->button() == MidButton
)
1820 // forward to current item
1821 int current
= currentItem();
1822 if (current
>= 0 && itemAt(current
))
1823 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1826 // rubberband move: draw the rubberband
1827 void KTreeView::draw_rubberband()
1830 * RB: I'm using a white pen because of the XorROP mode. I would prefer
1831 * to draw the rectangle in red but I don't now how to get a pen which
1832 * draws red in XorROP mode (this depends on the background). In fact
1833 * the color should be configurable.
1836 if (!rubberband_mode
) return;
1837 QPainter
paint(this);
1838 paint
.setPen(white
);
1839 paint
.setRasterOp(XorROP
);
1840 paint
.drawRect(xOffset()*viewWidth()/totalWidth(),
1841 yOffset()*viewHeight()/totalHeight(),
1842 rubber_width
+1, rubber_height
+1);
1846 // rubberband move: start move
1847 void KTreeView::start_rubberband(const QPoint
& where
)
1849 if (rubberband_mode
) { // Oops!
1852 /* RB: Don't now, if this check is necessary */
1853 if (!viewWidth() || !viewHeight()) return;
1854 if (!totalWidth() || !totalHeight()) return;
1856 // calculate the size of the rubberband rectangle
1857 rubber_width
= viewWidth()*viewWidth()/totalWidth();
1858 if (rubber_width
> viewWidth()) rubber_width
= viewWidth();
1859 rubber_height
= viewHeight()*viewHeight()/totalHeight();
1860 if (rubber_height
> viewHeight()) rubber_height
= viewHeight();
1862 // remember the cursor position and the actual offset
1863 rubber_startMouse
= where
;
1864 rubber_startX
= xOffset();
1865 rubber_startY
= yOffset();
1866 rubberband_mode
=TRUE
;
1870 // rubberband move: end move
1871 void KTreeView::end_rubberband()
1873 if (!rubberband_mode
) return;
1875 rubberband_mode
= FALSE
;
1878 // rubberband move: hanlde mouse moves
1879 void KTreeView::move_rubberband(const QPoint
& where
)
1881 if (!rubberband_mode
) return;
1883 // look how much the mouse moved and calc the new scroll position
1884 QPoint delta
= where
- rubber_startMouse
;
1885 int nx
= rubber_startX
+ delta
.x() * totalWidth() / viewWidth();
1886 int ny
= rubber_startY
+ delta
.y() * totalHeight() / viewHeight();
1888 // check the new position (and make it valid)
1890 else if (nx
> maxXOffset()) nx
= maxXOffset();
1892 else if (ny
> maxYOffset()) ny
= maxYOffset();
1894 // redraw the rubberband at the new position
1901 // paints the cell at the specified row and col
1902 // col is ignored for now since there is only one
1903 void KTreeView::paintCell(QPainter
* p
, int row
, int)
1905 KTreeViewItem
* item
= itemAt(row
);
1909 QColorGroup cg
= colorGroup();
1910 int indent
= indentation(item
);
1911 item
->paint(p
, indent
, cg
,
1912 current
== row
); /* highlighted */
1916 /* This is needed to make the kcontrol's color setup working (Marcin Dalecki) */
1917 void KTreeView::paletteChange(const QPalette
&)
1919 setBackgroundColor(colorGroup().base());
1924 /* raise the specified item up one slot in parent's subtree */
1925 void KTreeView::raiseItem(KTreeViewItem
*item
)
1927 KTreeViewItem
*itemParent
= item
->getParent();
1928 int itemChildIndex
= itemParent
->childIndex(item
);
1929 if(itemChildIndex
> 0) {
1930 bool autoU
= autoUpdate();
1931 setAutoUpdate(FALSE
);
1933 insertItem(itemParent
->childAt(--itemChildIndex
), item
, TRUE
);
1934 setAutoUpdate(autoU
);
1935 if(autoU
&& isVisible())
1940 // find the item at the path
1941 KTreeViewItem
* KTreeView::recursiveFind(KPath
& path
)
1947 QString
* searchString
= path
.pop();
1949 // find the parent item
1950 KTreeViewItem
* parent
= recursiveFind(path
);
1955 * Iterate through the parent's children searching for searchString.
1957 KTreeViewItem
* sibling
= parent
->getChild();
1958 while (sibling
!= 0) {
1959 if (*searchString
== sibling
->getText()) {
1960 break; /* found it! */
1962 sibling
= sibling
->getSibling();
1967 void KTreeView::setItemExpanded(KTreeViewItem
* item
)
1969 if (level(item
) < expansion
) {
1970 expandSubTree(item
, true);
1972 collapseSubTree(item
, true);
1976 // called by setExpandLevel for each item in tree
1977 bool KTreeView::setItemExpandLevel(KTreeViewItem
* item
, void*)
1979 assert(item
->owner
!= 0);
1980 item
->owner
->setItemExpanded(item
);
1984 // called by setExpandButtonDrawing for every item in tree
1985 // the parameter drawButton is used as (and implicitly cast to) a bool
1986 bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem
* item
,
1989 item
->setDrawExpandButton(drawButton
);
1993 // called by setShowItemText for every item in tree
1994 // the parameter newDrawText is used as (and implicitly cast to) a bool
1995 bool KTreeView::setItemShowText(KTreeViewItem
* item
,
1998 item
->setDrawText(newDrawText
);
2002 // called by setTreeDrawing for every item in tree
2003 // the parameter drawTree is used as (and implicitly cast to) a bool
2004 bool KTreeView::setItemTreeDrawing(KTreeViewItem
* item
, void* drawTree
)
2006 item
->setDrawTree(drawTree
);
2010 // makes the item a child of the item above it, splitting
2011 // the tree into a new branch
2012 void KTreeView::split(KTreeViewItem
*item
)
2014 KTreeViewItem
*itemParent
= item
->getParent();
2015 int itemChildIndex
= itemParent
->childIndex(item
);
2016 if(itemChildIndex
== 0)
2018 bool autoU
= autoUpdate();
2019 setAutoUpdate(FALSE
);
2021 appendChildItem(itemParent
->childAt(--itemChildIndex
), item
);
2022 setAutoUpdate(autoU
);
2023 if(autoU
&& isVisible())
2027 // removes the item from the tree without deleting it
2028 void KTreeView::takeItem(KTreeViewItem
* item
)
2030 assert(item
->owner
== this);
2032 // TODO: go over this function again
2034 bool wasVisible
= item
->isVisible();
2036 * If we have a current item, make sure that it is not in the subtree
2037 * that we are about to remove. If the current item is in the part
2038 * below the taken-out subtree, we must move it up a number of rows if
2039 * the taken-out subtree is at least partially visible.
2041 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
2042 if (wasVisible
&& cur
!= 0) {
2043 KTreeViewItem
* c
= cur
;
2044 while (c
!= 0 && c
!= item
) {
2048 // move current item to parent
2049 cur
= item
->getParent();
2050 if (cur
== treeRoot
)
2054 KTreeViewItem
* parentItem
= item
->getParent();
2055 parentItem
->removeChild(item
);
2057 if (wasVisible
|| parentItem
->childCount() == 0) {
2058 bool autoU
= autoUpdate();
2059 setAutoUpdate(FALSE
);
2060 updateVisibleItems();
2061 setAutoUpdate(autoU
);
2062 if (autoU
&& isVisible())
2066 // re-seat the current item
2067 setCurrentItem(cur
!= 0 ? itemRow(cur
) : -1);
2070 // visits each item, calculates the maximum width
2071 // and updates QTableView
2072 void KTreeView::updateCellWidth()
2074 // make cells at least 1 pixel wide to avoid singularities (division by zero)
2076 forEveryVisibleItem(&KTreeView::getMaxItemWidth
, &maxW
);
2077 maxItemWidth
= maxW
;
2081 int xoff
= xOffset();
2082 int yoff
= yOffset();
2083 if (xoff
> maxXOffset()) xoff
= maxXOffset();
2084 if (yoff
> maxYOffset()) yoff
= maxYOffset();
2086 setOffset(xoff
, yoff
);
2089 void KTreeView::updateVisibleItems()
2093 updateVisibleItemRec(treeRoot
, index
, count
);
2094 assert(index
== count
);
2099 void KTreeView::updateVisibleItemRec(KTreeViewItem
* item
, int& index
, int& count
)
2101 if (!item
->isExpanded()) {
2102 // no visible items if not expanded
2107 * Record the children of item in the list of visible items.
2109 * Don't register item itself, it's already in the list. Also only
2110 * allocate new space for children.
2112 count
+= item
->childCount();
2113 if (count
> itemCapacity
) {
2115 int newCapacity
= itemCapacity
;
2117 newCapacity
+= newCapacity
;
2118 } while (newCapacity
< count
);
2119 KTreeViewItem
** newItems
= new KTreeViewItem
*[newCapacity
];
2120 // clear the unneeded space
2121 for (int i
= index
; i
< newCapacity
; i
++) {
2124 // move already accumulated items over
2125 for (int i
= index
-1; i
>= 0; i
--) {
2126 newItems
[i
] = visibleItems
[i
];
2128 delete[] visibleItems
;
2129 visibleItems
= newItems
;
2130 itemCapacity
= newCapacity
;
2133 for (KTreeViewItem
* i
= item
->getChild(); i
!= 0; i
= i
->getSibling()) {
2134 visibleItems
[index
++] = i
;
2135 updateVisibleItemRec(i
, index
, count
);