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),
605 moveCurrentToSibling(false),
608 rubberband_mode(false)
615 setTableFlags(Tbl_autoScrollBars
| Tbl_clipCellPainting
| Tbl_snapToVGrid
);
616 clearTableFlags(Tbl_scrollLastVCell
| Tbl_scrollLastHCell
| Tbl_snapToVGrid
);
620 setFrameStyle(QFrame::WinPanel
| QFrame::Sunken
);
621 setBackgroundColor(colorGroup().base());
624 setFrameStyle(QFrame::Panel
| QFrame::Plain
);
628 setFocusPolicy(StrongFocus
);
630 setFocusPolicy(WheelFocus
);
632 treeRoot
= new KTreeViewItem
;
633 treeRoot
->setExpanded(true);
634 treeRoot
->owner
= this;
636 visibleItems
= new KTreeViewItem
*[itemCapacity
];
637 // clear those pointers
638 for (int j
= itemCapacity
-1; j
>= 0; j
--) {
644 KTreeView::~KTreeView()
648 delete[] visibleItems
;
652 // appends a child to the item at the given index with the given text
654 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
657 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
658 item
->setDeleteChildren(true);
659 appendChildItem(item
, index
);
662 // appends a child to the item at the end of the given path with
663 // the given text and pixmap
664 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
665 const KPath
& thePath
)
667 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
668 item
->setDeleteChildren(true);
669 appendChildItem(item
, thePath
);
672 // appends the given item to the children of the item at the given index
673 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, int index
)
675 /* find parent item and append new item to parent's sub tree */
676 KTreeViewItem
* parentItem
= itemAt(index
);
679 appendChildItem(parentItem
, newItem
);
682 // appends the given item to the children of the item at the end of the
684 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, const KPath
& thePath
)
686 /* find parent item and append new item to parent's sub tree */
687 KTreeViewItem
* parentItem
= itemAt(thePath
);
690 appendChildItem(parentItem
, newItem
);
693 // indicates whether horizontal scrollbar appears only when needed
694 bool KTreeView::autoBottomScrollBar() const
696 return testTableFlags(Tbl_autoHScrollBar
);
699 // indicates whether vertical scrollbar appears only when needed
700 bool KTreeView::autoScrollBar() const
702 return testTableFlags(Tbl_autoVScrollBar
);
705 // indicates whether display updates automatically on changes
706 bool KTreeView::autoUpdate() const
708 return QTableView::autoUpdate();
711 // indicates whether horizontal scrollbar is present
712 bool KTreeView::bottomScrollBar() const
714 return testTableFlags(Tbl_hScrollBar
);
717 // translate mouse coord to cell coord
718 QPoint
KTreeView::cellCoords(int row
, const QPoint
& widgetCoord
)
720 int cellX
= 0, cellY
= 0;
722 rowYPos(row
, &cellY
);
723 return QPoint(widgetCoord
.x() - cellX
, widgetCoord
.y() - cellY
);
726 // find item at specified index and change pixmap and/or text
727 void KTreeView::changeItem(const char *newText
,
728 const QPixmap
*newPixmap
,
731 KTreeViewItem
*item
= itemAt(index
);
733 changeItem(item
, index
, newText
, newPixmap
);
736 // find item at end of specified path, and change pixmap and/or text
737 void KTreeView::changeItem(const char* newText
,
738 const QPixmap
* newPixmap
,
739 const KPath
& thePath
)
741 KTreeViewItem
* item
= itemAt(thePath
);
743 int index
= itemRow(item
);
744 changeItem(item
, index
, newText
, newPixmap
);
748 // clear all items from list and erase display
749 void KTreeView::clear()
753 /* somewhat of a hack for takeItem so it doesn't update the current item... */
756 bool autoU
= autoUpdate();
757 setAutoUpdate(FALSE
);
758 QStack
<KTreeViewItem
> stack
;
759 stack
.push(treeRoot
);
760 while(!stack
.isEmpty()) {
761 KTreeViewItem
*item
= stack
.pop();
762 if(item
->hasChild()) {
764 stack
.push(item
->getChild());
766 else if(item
->hasSibling()) {
768 stack
.push(item
->getSibling());
770 else if(item
->getParent() != 0) {
776 if(goingDown
|| QApplication::closingDown())
778 setAutoUpdate(autoU
);
779 if(autoU
&& isVisible())
783 // return a count of all the items in the tree, whether visible or not
784 uint
KTreeView::count()
787 forEveryItem(&KTreeView::countItem
, (void *)&total
);
791 // returns the index of the current (highlighted) item
792 int KTreeView::currentItem() const
797 // collapses the item at the specified row index.
798 void KTreeView::collapseItem(int index
, bool emitSignal
)
800 KTreeViewItem
* item
= itemAt(index
);
802 collapseSubTree(item
, emitSignal
);
805 // expands the item at the specified row indes.
806 void KTreeView::expandItem(int index
, bool emitSignal
)
808 KTreeViewItem
* item
= itemAt(index
);
810 expandSubTree(item
, emitSignal
);
813 // returns the depth the tree is automatically expanded to when
815 int KTreeView::expandLevel() const
820 // visits every item in the tree, visible or not and applies
821 // the user supplied function with the item and user data passed as parameters
822 // if user supplied function returns true, traversal ends and function returns
823 bool KTreeView::forEveryItem(KForEveryFunc func
, void* user
, KTreeViewItem
* item
)
828 assert(item
->owner
== this);
829 item
= item
->getChild();
832 // visit the siblings
833 if ((*func
)(item
, user
)) {
836 // visit the children (recursively)
837 if (item
->hasChild()) {
838 if (forEveryItem(func
, user
, item
))
841 item
= item
->getSibling();
846 // visits every visible item in the tree in order and applies the
847 // user supplied function with the item and user data passed as parameters
848 // if user supplied function returns TRUE, traversal ends and function
850 bool KTreeView::forEveryVisibleItem(KForEveryFunc func
, void *user
,
856 // children are invisible (hence, nothing to do)
857 // if item is invisible or collapsed
858 if (!item
->isVisible() || !item
->isExpanded()) {
862 assert(item
->owner
== this);
863 item
= item
->getChild();
866 // visit the siblings
867 if ((*func
)(item
, user
)) {
870 // visit the children (recursively)
871 if (item
->hasChild() && item
->isExpanded()) {
872 if (forEveryVisibleItem(func
, user
, item
))
875 item
= item
->getSibling();
880 // returns a pointer to the KTreeViewItem at the current index
881 // or 0 if no current item
882 KTreeViewItem
*KTreeView::getCurrentItem()
884 if(current
== -1) return 0;
885 return itemAt(current
);
888 // returns the current indent spacing
889 int KTreeView::indentSpacing()
894 // inserts a new item with the specified text and pixmap before
895 // or after the item at the given index, depending on the value
897 // if index is negative, appends item to tree at root level
898 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
899 int row
, bool prefix
)
901 KTreeViewItem
* refItem
= itemAt(row
);
903 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
904 item
->setDeleteChildren(true);
906 bool success
= insertItem(refItem
, item
, prefix
);
912 // inserts a new item with the specified text and pixmap before
913 // or after the item at the end of the given path, depending on the value
915 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
916 const KPath
& path
, bool prefix
)
918 KTreeViewItem
* refItem
= itemAt(path
);
920 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
921 item
->setDeleteChildren(true);
923 bool success
= insertItem(refItem
, item
, prefix
);
929 // inserts the given item or derived object into the tree before
930 // or after the item at the given index, depending on the value
932 // if index is negative, appends item to tree at root level
933 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
934 int index
, bool prefix
)
936 // find the item currently at the index, if there is one
937 KTreeViewItem
* refItem
= itemAt(index
);
939 // insert new item at the appropriate place
940 return insertItem(refItem
, newItem
, prefix
);
943 // inserts the given item or derived object into the tree before
944 // or after the item at the end of the given path, depending on the value
946 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
947 const KPath
& thePath
, bool prefix
)
949 // find the item currently at the end of the path, if there is one
950 KTreeViewItem
* refItem
= itemAt(thePath
);
952 // insert new item at appropriate place
953 return insertItem(refItem
, newItem
, prefix
);
957 * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
960 KTreeViewItem
* KTreeView::itemAt(int row
)
962 if (row
< 0 || row
>= numRows()) {
966 // lookup the item in the list of visible items
967 assert(row
< itemCapacity
);
968 KTreeViewItem
* i
= visibleItems
[row
];
974 // returns pointer to KTreeViewItem at the end of the
975 // path or 0 if not found
976 KTreeViewItem
* KTreeView::itemAt(const KPath
& path
)
981 // need a copy of the path because recursiveFind will destroy it
983 pathCopy
.setAutoDelete(false);
986 return recursiveFind(pathCopy
);
989 // computes the path of the item at the specified index
990 // if index is invalid, nothing is done.
991 void KTreeView::itemPath(int row
, KPath
& path
)
993 KTreeViewItem
* item
= itemAt(row
);
995 itemPath(item
, path
);
999 // returns the row in the visible tree of the given item or
1001 int KTreeView::itemRow(KTreeViewItem
* item
)
1003 if (item
->owner
== this) {
1004 // search in list of visible items
1005 for (int i
= numRows()-1; i
>= 0; i
--) {
1006 if (visibleItems
[i
] == item
) {
1016 * move the subtree at the specified index up one branch level (make root
1017 * item a sibling of its current parent)
1019 void KTreeView::join(int index
)
1021 KTreeViewItem
*item
= itemAt(index
);
1027 * move the subtree at the specified index up one branch level (make root
1028 * item a sibling of it's current parent)
1030 void KTreeView::join(const KPath
& path
)
1032 KTreeViewItem
*item
= itemAt(path
);
1037 /* move item at specified index one slot down in its parent's sub tree */
1038 void KTreeView::lowerItem(int index
)
1040 KTreeViewItem
*item
= itemAt(index
);
1045 /* move item at specified path one slot down in its parent's sub tree */
1046 void KTreeView::lowerItem(const KPath
& path
)
1048 KTreeViewItem
* item
= itemAt(path
);
1053 /* move item at specified index one slot up in its parent's sub tree */
1054 void KTreeView::raiseItem(int index
)
1056 KTreeViewItem
* item
= itemAt(index
);
1061 /* move item at specified path one slot up in its parent's sub tree */
1062 void KTreeView::raiseItem(const KPath
& path
)
1064 KTreeViewItem
* item
= itemAt(path
);
1069 // remove the item at the specified index and delete it
1070 void KTreeView::removeItem(int index
)
1072 KTreeViewItem
*item
= itemAt(index
);
1079 // remove the item at the end of the specified path and delete it
1080 void KTreeView::removeItem(const KPath
& thePath
)
1082 KTreeViewItem
* item
= itemAt(thePath
);
1089 // indicates whether vertical scrollbar is present
1090 bool KTreeView::scrollBar() const
1092 return testTableFlags(Tbl_vScrollBar
);
1095 void KTreeView::scrollVisible(KTreeViewItem
* item
, bool children
)
1099 int row
= itemRow(item
);
1101 return; /* do nothing if invisible */
1103 if (children
&& item
->isExpanded()) {
1104 // we are concerned about children
1105 if (!rowIsVisible(row
)) {
1106 // just move to the top
1109 // this is the complicated part
1110 // count the visible children (including grandchildren)
1112 forEveryVisibleItem(countItem
, &numVisible
, item
);
1113 // if the last child is visible, do nothing
1114 if (rowIsVisible(row
+ numVisible
))
1117 * Basically, item will become the top cell; but if there are
1118 * more visible rows in the widget than we have children, then
1119 * we don't move that far.
1121 int remain
= lastRowVisible()-topCell()-numVisible
;
1125 setTopCell(QMAX(0,row
-remain
));
1129 // we are not concerned about children
1130 if (rowIsVisible(row
))
1132 // just move the item to the top
1137 // enables/disables auto update of display
1138 void KTreeView::setAutoUpdate(bool enable
)
1140 QTableView::setAutoUpdate(enable
);
1143 // enables/disables horizontal scrollbar
1144 void KTreeView::setBottomScrollBar(bool enable
)
1146 enable
? setTableFlags(Tbl_hScrollBar
) :
1147 clearTableFlags(Tbl_hScrollBar
);
1150 // sets the current item and hightlights it, emitting signals
1151 void KTreeView::setCurrentItem(int row
)
1155 int numVisible
= numRows();
1156 if (row
> numVisible
)
1158 int oldCurrent
= current
;
1160 if (oldCurrent
< numVisible
)
1161 updateCell(oldCurrent
, 0);
1163 updateCell(current
, 0, false);
1164 emit
highlighted(current
);
1168 // enables/disables drawing of expand button
1169 void KTreeView::setExpandButtonDrawing(bool enable
)
1171 if (drawExpandButton
== enable
)
1173 drawExpandButton
= enable
;
1175 // the user parameter is cast to a bool in setItemExpandButtonDrawing
1176 forEveryItem(&KTreeView::setItemExpandButtonDrawing
, enable
? &enable
: 0);
1178 if (autoUpdate() && isVisible())
1182 // sets depth to which subtrees are automatically expanded, and
1183 // redraws tree if auto update enabled
1184 void KTreeView::setExpandLevel(int level
)
1186 if (expansion
== level
)
1189 KTreeViewItem
* item
= getCurrentItem();
1190 forEveryItem(&KTreeView::setItemExpandLevel
, 0);
1192 if (item
->getParent()->isExpanded())
1194 item
= item
->getParent();
1197 setCurrentItem(itemRow(item
));
1198 if (autoUpdate() && isVisible())
1202 // sets the indent margin for all branches and repaints if auto update enabled
1203 void KTreeView::setIndentSpacing(int spacing
)
1205 if (itemIndent
== spacing
)
1207 itemIndent
= spacing
;
1209 if (autoUpdate() && isVisible())
1213 void KTreeView::setMoveCurrentToSibling(bool m
)
1215 moveCurrentToSibling
= m
;
1218 // enables/disables vertical scrollbar
1219 void KTreeView::setScrollBar(bool enable
)
1221 enable
? setTableFlags(Tbl_vScrollBar
) :
1222 clearTableFlags(Tbl_vScrollBar
);
1225 // enables/disables display of item text (keys)
1226 void KTreeView::setShowItemText(bool enable
)
1228 if (showText
== enable
)
1232 // the user parameter is cast to a bool in setItemShowText
1233 forEveryItem(&KTreeView::setItemShowText
, enable
? &enable
: 0);
1235 if (autoUpdate() && isVisible())
1239 // indicates whether vertical scrolling is by pixel or row
1240 void KTreeView::setSmoothScrolling(bool enable
)
1242 enable
? setTableFlags(Tbl_smoothVScrolling
) :
1243 clearTableFlags(Tbl_smoothVScrolling
);
1246 // enables/disables tree branch drawing
1247 void KTreeView::setTreeDrawing(bool enable
)
1249 if (drawTree
== enable
)
1253 // the user parameter is cast to a bool in setItemTreeDrawing
1254 forEveryItem(&KTreeView::setItemTreeDrawing
, enable
? &enable
: 0);
1256 if (autoUpdate() && isVisible())
1260 // indicates whether item text keys are displayed
1261 bool KTreeView::showItemText() const
1266 // indicates whether scrolling is by pixel or row
1267 bool KTreeView::smoothScrolling() const
1269 return testTableFlags(Tbl_smoothVScrolling
);
1272 // indents the item at the given index, splitting the tree into
1274 void KTreeView::split(int index
)
1276 KTreeViewItem
*item
= itemAt(index
);
1281 // indents the item at the given path, splitting the tree into
1283 void KTreeView::split(const KPath
& path
)
1285 KTreeViewItem
* item
= itemAt(path
);
1290 // removes item at specified index from tree but does not delete it
1291 // returns pointer to the item or 0 if not succesful
1292 KTreeViewItem
*KTreeView::takeItem(int index
)
1294 KTreeViewItem
*item
= itemAt(index
);
1300 // removes item at specified path from tree but does not delete it
1301 // returns pointer to the item or 0 if not successful
1302 KTreeViewItem
* KTreeView::takeItem(const KPath
& path
)
1304 KTreeViewItem
* item
= itemAt(path
);
1310 // indicates whether tree branches are drawn
1311 bool KTreeView::treeDrawing() const
1317 // appends a child to the specified parent item (note: a child, not a sibling, is added!)
1318 void KTreeView::appendChildItem(KTreeViewItem
* theParent
,
1319 KTreeViewItem
* newItem
)
1321 theParent
->appendChild(newItem
);
1324 newItem
->setDrawExpandButton(drawExpandButton
);
1325 newItem
->setDrawTree(drawTree
);
1326 newItem
->setDrawText(showText
);
1327 if (level(newItem
) < expansion
) {
1328 newItem
->setExpanded(true);
1331 // fix up branch levels of any children that the new item may already have
1332 if(newItem
->hasChild()) {
1333 fixChildren(newItem
);
1336 // if necessary, adjust cell width, number of rows and repaint
1337 if (newItem
->isVisible() || theParent
->childCount() == 1) {
1338 bool autoU
= autoUpdate();
1339 setAutoUpdate(false);
1340 updateVisibleItems();
1341 setAutoUpdate(autoU
);
1342 if (autoU
&& isVisible())
1347 // returns the height of the cell(row) at the specified row (index)
1348 int KTreeView::cellHeight(int row
)
1350 return itemAt(row
)->height(fontMetrics());
1353 // returns the width of the cells. Note: this is mostly for derived classes
1354 // which have more than 1 column
1355 int KTreeView::cellWidth(int /*col*/)
1357 return maxItemWidth
;
1360 // changes the given item with the new text and/or pixmap
1361 void KTreeView::changeItem(KTreeViewItem
* toChange
, int itemRow
,
1362 const char* newText
, const QPixmap
* newPixmap
)
1364 int indent
= indentation(toChange
);
1365 int oldWidth
= toChange
->width(indent
);
1367 toChange
->setText(newText
);
1369 toChange
->setPixmap(*newPixmap
);
1370 if(oldWidth
!= toChange
->width(indent
))
1374 if(autoUpdate() && rowIsVisible(itemRow
))
1375 updateCell(itemRow
, 0);
1378 // collapses the subtree at the specified item
1379 void KTreeView::collapseSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1381 assert(subRoot
->owner
== this);
1382 if (!subRoot
->isExpanded())
1385 // must move the current item if it is visible
1386 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1388 subRoot
->setExpanded(false);
1389 if (subRoot
->isVisible()) {
1390 bool autoU
= autoUpdate();
1391 setAutoUpdate(false);
1392 updateVisibleItems();
1393 // re-seat current item
1395 setCurrentItem(itemRow(cur
));
1398 emit
collapsed(itemRow(subRoot
));
1400 setAutoUpdate(autoU
);
1401 if (autoU
&& isVisible())
1406 // used by count() with forEach() function to count total number
1407 // of items in the tree
1408 bool KTreeView::countItem(KTreeViewItem
*, void* total
)
1410 int* t
= static_cast<int*>(total
);
1415 // expands the subtree at the given item
1416 void KTreeView::expandSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1418 assert(subRoot
->owner
== this);
1419 if (subRoot
->isExpanded())
1422 // must move the current item if it is visible
1423 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1427 if (subRoot
->delayedExpanding
) {
1428 emit
expanding(subRoot
, allow
);
1433 subRoot
->setExpanded(true);
1435 if (subRoot
->isVisible()) {
1436 bool autoU
= autoUpdate();
1437 setAutoUpdate(false);
1438 updateVisibleItems();
1439 // re-seat current item
1441 setCurrentItem(itemRow(cur
));
1444 emit
expanded(itemRow(subRoot
));
1446 setAutoUpdate(autoU
);
1447 if (autoU
&& isVisible())
1452 // fix up branch levels out of whack from split/join operations on the tree
1453 void KTreeView::fixChildren(KTreeViewItem
*parentItem
)
1455 KTreeViewItem
* childItem
= 0;
1456 KTreeViewItem
* siblingItem
= 0;
1457 // int childBranch = parentItem->getBranch() + 1;
1458 if(parentItem
->hasChild()) {
1459 childItem
= parentItem
->getChild();
1460 // childItem->setBranch(childBranch);
1461 childItem
->owner
= parentItem
->owner
;
1462 fixChildren(childItem
);
1464 while(childItem
&& childItem
->hasSibling()) {
1465 siblingItem
= childItem
->getSibling();
1466 // siblingItem->setBranch(childBranch);
1467 siblingItem
->owner
= parentItem
->owner
;
1468 fixChildren(siblingItem
);
1469 childItem
= siblingItem
;
1474 * Handle QFocusEvent processing by setting current item to top row if
1475 * there is no current item, and updates cell to add or delete the focus
1476 * rectangle on the highlight bar. The base class is not called because it
1477 * does a repaint() which causes flicker.
1479 void KTreeView::focusInEvent(QFocusEvent
*)
1481 if (current
< 0 && numRows() > 0)
1482 setCurrentItem(topCell());
1483 updateCell(current
, 0);
1486 void KTreeView::focusOutEvent(QFocusEvent
*)
1488 updateCell(current
, 0);
1491 // called by updateCellWidth() for each item in the visible list
1492 bool KTreeView::getMaxItemWidth(KTreeViewItem
* item
, void* user
)
1494 assert(item
->owner
!= 0);
1495 int indent
= item
->owner
->indentation(item
);
1496 int* maxW
= static_cast<int*>(user
);
1497 int w
= item
->width(indent
);
1503 int KTreeView::indentation(KTreeViewItem
* item
) const
1505 return level(item
) * itemIndent
+ itemIndent
+ 3;
1508 // inserts the new item before or after the reference item, depending
1509 // on the value of prefix
1510 bool KTreeView::insertItem(KTreeViewItem
* referenceItem
,
1511 KTreeViewItem
* newItem
,
1514 assert(newItem
!= 0);
1515 assert(referenceItem
== 0 || referenceItem
->owner
== this);
1517 /* set the new item's state */
1518 newItem
->setDrawExpandButton(drawExpandButton
);
1519 newItem
->setDrawTree(drawTree
);
1520 newItem
->setDrawText(showText
);
1521 KTreeViewItem
* parentItem
;
1522 if (referenceItem
) {
1523 parentItem
= referenceItem
->getParent();
1524 int insertIndex
= parentItem
->childIndex(referenceItem
);
1527 parentItem
->insertChild(insertIndex
, newItem
);
1530 // no reference item, append at end of visible tree
1532 parentItem
= treeRoot
;
1533 parentItem
->appendChild(newItem
);
1536 // set item expansion
1537 if (level(newItem
) < expansion
)
1538 newItem
->setExpanded(true);
1540 // fix up branch levels of any children
1541 if (newItem
->hasChild())
1542 fixChildren(newItem
);
1544 // if repaint necessary, do it if visible and auto update
1546 if (newItem
->isVisible() || parentItem
->childCount() == 1) {
1547 bool autoU
= autoUpdate();
1548 setAutoUpdate(FALSE
);
1549 updateVisibleItems();
1550 setAutoUpdate(autoU
);
1551 if (autoU
&& isVisible())
1558 * returns pointer to item's path
1560 void KTreeView::itemPath(KTreeViewItem
* item
, KPath
& path
) const
1563 assert(item
->owner
== this);
1564 if (item
!= treeRoot
) {
1565 itemPath(item
->getParent(), path
);
1566 path
.push(new QString(item
->getText()));
1571 * joins the item's branch into the tree, making the item a sibling of its
1574 void KTreeView::join(KTreeViewItem
*item
)
1576 KTreeViewItem
*itemParent
= item
->getParent();
1577 if(itemParent
->hasParent()) {
1578 bool autoU
= autoUpdate();
1579 setAutoUpdate(FALSE
);
1581 insertItem(itemParent
, item
, FALSE
);
1582 setAutoUpdate(autoU
);
1583 if(autoU
&& isVisible())
1588 // handles keyboard interface
1589 void KTreeView::keyPressEvent(QKeyEvent
* e
)
1592 return; /* nothing to do */
1594 /* if there's no current item, make the top item current */
1595 if (currentItem() < 0)
1596 setCurrentItem(topCell());
1597 assert(currentItem() >= 0); /* we need a current item */
1598 assert(itemAt(currentItem()) != 0); /* we really need a current item */
1600 // give currentItem a chance to handle the event
1601 if (itemAt(currentItem())->keyEvent(e
))
1602 return; /* handled */
1604 int pageSize
, delta
;
1605 KTreeViewItem
* item
;
1610 // make previous item current, scroll up if necessary
1611 if (currentItem() > 0) {
1612 setCurrentItem(currentItem() - 1);
1613 scrollVisible(itemAt(currentItem()), false);
1617 // make next item current, scroll down if necessary
1618 if (currentItem() < numRows() - 1) {
1619 setCurrentItem(currentItem() + 1);
1620 if (currentItem() > lastRowVisible()) {
1621 // scrollVisible is not feasible here because
1622 // it scrolls the item to the top
1623 setTopCell(topCell() + currentItem() - lastRowVisible());
1624 } else if (currentItem() < topCell()) {
1625 setTopCell(currentItem());
1630 // move highlight one page down and scroll down
1631 delta
= currentItem() - topCell();
1632 pageSize
= lastRowVisible() - topCell();
1633 setTopCell(QMIN(topCell() + pageSize
, numRows() - 1));
1634 setCurrentItem(QMIN(topCell() + delta
, numRows() - 1));
1637 // move highlight one page up and scroll up
1638 delta
= currentItem() - topCell();
1639 pageSize
= lastRowVisible() - topCell();
1640 setTopCell(QMAX(topCell() - pageSize
, 0));
1641 setCurrentItem(QMAX(topCell() + delta
, 0));
1645 // if current item has subtree and is collapsed, expand it
1646 item
= itemAt(currentItem());
1647 if (item
->isExpanded() && item
->hasChild() && key
== Key_Right
) {
1648 // going right on an expanded item is like going down
1652 expandSubTree(item
, true);
1653 scrollVisible(item
, true);
1658 // if current item has subtree and is expanded, collapse it
1659 item
= itemAt(currentItem());
1660 if ((!item
->isExpanded() || !item
->hasChild()) && key
== Key_Left
) {
1661 // going left on a collapsed item goes to its parent
1662 item
= item
->getParent();
1663 if (item
== treeRoot
)
1664 break; /* we're already at the top */
1665 assert(item
->isVisible());
1666 setCurrentItem(itemRow(item
));
1668 collapseSubTree(item
, true);
1670 scrollVisible(item
, false);
1674 // select the current item
1675 if (currentItem() >= 0)
1676 emit
selected(currentItem());
1683 // handles keyboard interface
1684 void KTreeView::keyReleaseEvent(QKeyEvent
* e
)
1686 if (currentItem() >= 0 && itemAt(currentItem()) != 0)
1687 itemAt(currentItem())->keyEvent(e
);
1690 int KTreeView::level(KTreeViewItem
* item
) const
1693 assert(item
->owner
== this);
1694 assert(item
!= treeRoot
);
1696 item
= item
->parent
->parent
; /* since item != treeRoot, there is a parent */
1698 item
= item
->parent
;
1704 /* move specified item down one slot in parent's subtree */
1705 void KTreeView::lowerItem(KTreeViewItem
*item
)
1707 KTreeViewItem
*itemParent
= item
->getParent();
1708 uint itemChildIndex
= itemParent
->childIndex(item
);
1709 if(itemChildIndex
< itemParent
->childCount() - 1) {
1710 bool autoU
= autoUpdate();
1711 setAutoUpdate(FALSE
);
1713 insertItem(itemParent
->childAt(itemChildIndex
), item
, FALSE
);
1714 setAutoUpdate(autoU
);
1715 if(autoU
&& isVisible())
1720 // handle mouse double click events by selecting the clicked item
1721 // and emitting the signal
1722 void KTreeView::mouseDoubleClickEvent(QMouseEvent
* e
)
1724 // find out which row has been clicked
1725 int itemClicked
= findRow(e
->y());
1727 if (itemClicked
< 0)
1728 return; /* invalid row, do nothing */
1730 KTreeViewItem
* item
= itemAt(itemClicked
);
1734 // translate mouse coord to cell coord
1735 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1738 if (item
->mouseEvent(e
, cellCoord
))
1742 int indent
= indentation(item
);
1743 if (item
->boundingRect(indent
).contains(cellCoord
))
1744 emit
selected(itemClicked
);
1747 // handle mouse movement events
1748 void KTreeView::mouseMoveEvent(QMouseEvent
* e
)
1750 // in rubberband_mode we actually scroll the window now
1751 if (rubberband_mode
) {
1752 move_rubberband(e
->pos());
1754 // else forward to current item
1755 int current
= currentItem();
1756 if (current
>= 0 && itemAt(current
))
1757 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1762 // handle single mouse presses
1763 void KTreeView::mousePressEvent(QMouseEvent
* e
)
1765 /* first: cancel rubberbanding if it's on */
1766 if (rubberband_mode
)
1768 // another button was pressed while rubberbanding, stop the move.
1769 // RB: if we allow other buttons while rubberbanding the tree can expand
1770 // while rubberbanding - we then need to recalculate and resize the
1771 // rubberband rect and show the new size
1776 // find out which row has been clicked
1777 int itemClicked
= findRow(e
->y());
1779 // nothing to do if not on valid row
1780 if (itemClicked
< 0)
1782 KTreeViewItem
* item
= itemAt(itemClicked
);
1786 // translate mouse coord to cell coord
1787 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1789 // give the item a crack
1790 if (item
->mouseEvent(e
, cellCoord
))
1791 return; /* event eaten by item */
1793 // check for rubberbanding
1794 if (e
->button() == MidButton
)
1796 // RB: the MMB is hardcoded to the "rubberband" scroll mode
1797 if (!rubberband_mode
) {
1798 start_rubberband(e
->pos());
1803 if (e
->button() == RightButton
) {
1804 emit
rightPressed(itemClicked
, e
->pos());
1806 /* hit test expand button (doesn't set currentItem) */
1807 else if (item
->expandButtonClicked(cellCoord
)) {
1808 if (item
->isExpanded()) {
1809 collapseSubTree(item
, true);
1811 expandSubTree(item
, true);
1812 scrollVisible(item
, true); /* make children visible */
1816 else if (item
->boundingRect(indentation(item
)).contains(cellCoord
)) {
1817 setCurrentItem(itemClicked
);
1821 // handle mouse release events
1822 void KTreeView::mouseReleaseEvent(QMouseEvent
*e
)
1824 /* if it's the MMB end rubberbanding */
1825 if (rubberband_mode
) {
1826 if (e
->button() == MidButton
)
1830 // forward to current item
1831 int current
= currentItem();
1832 if (current
>= 0 && itemAt(current
))
1833 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1836 // rubberband move: draw the rubberband
1837 void KTreeView::draw_rubberband()
1840 * RB: I'm using a white pen because of the XorROP mode. I would prefer
1841 * to draw the rectangle in red but I don't now how to get a pen which
1842 * draws red in XorROP mode (this depends on the background). In fact
1843 * the color should be configurable.
1846 if (!rubberband_mode
) return;
1847 QPainter
paint(this);
1848 paint
.setPen(white
);
1849 paint
.setRasterOp(XorROP
);
1850 paint
.drawRect(xOffset()*viewWidth()/totalWidth(),
1851 yOffset()*viewHeight()/totalHeight(),
1852 rubber_width
+1, rubber_height
+1);
1856 // rubberband move: start move
1857 void KTreeView::start_rubberband(const QPoint
& where
)
1859 if (rubberband_mode
) { // Oops!
1862 /* RB: Don't now, if this check is necessary */
1863 if (!viewWidth() || !viewHeight()) return;
1864 if (!totalWidth() || !totalHeight()) return;
1866 // calculate the size of the rubberband rectangle
1867 rubber_width
= viewWidth()*viewWidth()/totalWidth();
1868 if (rubber_width
> viewWidth()) rubber_width
= viewWidth();
1869 rubber_height
= viewHeight()*viewHeight()/totalHeight();
1870 if (rubber_height
> viewHeight()) rubber_height
= viewHeight();
1872 // remember the cursor position and the actual offset
1873 rubber_startMouse
= where
;
1874 rubber_startX
= xOffset();
1875 rubber_startY
= yOffset();
1876 rubberband_mode
=TRUE
;
1880 // rubberband move: end move
1881 void KTreeView::end_rubberband()
1883 if (!rubberband_mode
) return;
1885 rubberband_mode
= FALSE
;
1888 // rubberband move: hanlde mouse moves
1889 void KTreeView::move_rubberband(const QPoint
& where
)
1891 if (!rubberband_mode
) return;
1893 // look how much the mouse moved and calc the new scroll position
1894 QPoint delta
= where
- rubber_startMouse
;
1895 int nx
= rubber_startX
+ delta
.x() * totalWidth() / viewWidth();
1896 int ny
= rubber_startY
+ delta
.y() * totalHeight() / viewHeight();
1898 // check the new position (and make it valid)
1900 else if (nx
> maxXOffset()) nx
= maxXOffset();
1902 else if (ny
> maxYOffset()) ny
= maxYOffset();
1904 // redraw the rubberband at the new position
1911 // paints the cell at the specified row and col
1912 // col is ignored for now since there is only one
1913 void KTreeView::paintCell(QPainter
* p
, int row
, int)
1915 KTreeViewItem
* item
= itemAt(row
);
1919 QColorGroup cg
= colorGroup();
1920 int indent
= indentation(item
);
1921 item
->paint(p
, indent
, cg
,
1922 current
== row
); /* highlighted */
1926 /* This is needed to make the kcontrol's color setup working (Marcin Dalecki) */
1927 void KTreeView::paletteChange(const QPalette
&)
1929 setBackgroundColor(colorGroup().base());
1934 /* raise the specified item up one slot in parent's subtree */
1935 void KTreeView::raiseItem(KTreeViewItem
*item
)
1937 KTreeViewItem
*itemParent
= item
->getParent();
1938 int itemChildIndex
= itemParent
->childIndex(item
);
1939 if(itemChildIndex
> 0) {
1940 bool autoU
= autoUpdate();
1941 setAutoUpdate(FALSE
);
1943 insertItem(itemParent
->childAt(--itemChildIndex
), item
, TRUE
);
1944 setAutoUpdate(autoU
);
1945 if(autoU
&& isVisible())
1950 // find the item at the path
1951 KTreeViewItem
* KTreeView::recursiveFind(KPath
& path
)
1957 QString
* searchString
= path
.pop();
1959 // find the parent item
1960 KTreeViewItem
* parent
= recursiveFind(path
);
1965 * Iterate through the parent's children searching for searchString.
1967 KTreeViewItem
* sibling
= parent
->getChild();
1968 while (sibling
!= 0) {
1969 if (*searchString
== sibling
->getText()) {
1970 break; /* found it! */
1972 sibling
= sibling
->getSibling();
1977 void KTreeView::setItemExpanded(KTreeViewItem
* item
)
1979 if (level(item
) < expansion
) {
1980 expandSubTree(item
, true);
1982 collapseSubTree(item
, true);
1986 // called by setExpandLevel for each item in tree
1987 bool KTreeView::setItemExpandLevel(KTreeViewItem
* item
, void*)
1989 assert(item
->owner
!= 0);
1990 item
->owner
->setItemExpanded(item
);
1994 // called by setExpandButtonDrawing for every item in tree
1995 // the parameter drawButton is used as (and implicitly cast to) a bool
1996 bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem
* item
,
1999 item
->setDrawExpandButton(drawButton
);
2003 // called by setShowItemText for every item in tree
2004 // the parameter newDrawText is used as (and implicitly cast to) a bool
2005 bool KTreeView::setItemShowText(KTreeViewItem
* item
,
2008 item
->setDrawText(newDrawText
);
2012 // called by setTreeDrawing for every item in tree
2013 // the parameter drawTree is used as (and implicitly cast to) a bool
2014 bool KTreeView::setItemTreeDrawing(KTreeViewItem
* item
, void* drawTree
)
2016 item
->setDrawTree(drawTree
);
2020 // makes the item a child of the item above it, splitting
2021 // the tree into a new branch
2022 void KTreeView::split(KTreeViewItem
*item
)
2024 KTreeViewItem
*itemParent
= item
->getParent();
2025 int itemChildIndex
= itemParent
->childIndex(item
);
2026 if(itemChildIndex
== 0)
2028 bool autoU
= autoUpdate();
2029 setAutoUpdate(FALSE
);
2031 appendChildItem(itemParent
->childAt(--itemChildIndex
), item
);
2032 setAutoUpdate(autoU
);
2033 if(autoU
&& isVisible())
2037 // removes the item from the tree without deleting it
2038 void KTreeView::takeItem(KTreeViewItem
* item
)
2040 assert(item
->owner
== this);
2042 // TODO: go over this function again
2044 bool wasVisible
= item
->isVisible();
2046 * If we have a current item, make sure that it is not in the subtree
2047 * that we are about to remove. If the current item is in the part
2048 * below the taken-out subtree, we must move it up a number of rows if
2049 * the taken-out subtree is at least partially visible.
2051 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
2052 KTreeViewItem
* oldCurrent
= cur
;
2053 if (wasVisible
&& cur
!= 0) {
2054 KTreeViewItem
* c
= cur
;
2055 while (c
!= 0 && c
!= item
) {
2059 // move current item to parent
2060 cur
= item
->getParent();
2061 if (cur
== treeRoot
) {
2063 // move it to next or previous sibling
2064 if (moveCurrentToSibling
) {
2065 if (item
->getSibling() != 0) {
2066 cur
= item
->getSibling();
2067 } else if (treeRoot
->getChild() != item
) {
2068 cur
= treeRoot
->getChild();
2069 while (cur
!= 0 && cur
->getSibling() != item
)
2070 cur
= cur
->getSibling();
2076 KTreeViewItem
* parentItem
= item
->getParent();
2077 parentItem
->removeChild(item
);
2079 if (wasVisible
|| parentItem
->childCount() == 0) {
2080 bool autoU
= autoUpdate();
2081 setAutoUpdate(FALSE
);
2082 updateVisibleItems();
2083 setAutoUpdate(autoU
);
2084 if (autoU
&& isVisible())
2088 // re-seat the current item
2089 // row changes if cur is below the taken item
2090 current
= cur
!= 0 ? itemRow(cur
) : -1;
2091 // signal must be emitted only if item really changed
2092 if (cur
!= oldCurrent
) {
2093 updateCell(current
, 0, false);
2094 emit
highlighted(current
);
2098 // visits each item, calculates the maximum width
2099 // and updates QTableView
2100 void KTreeView::updateCellWidth()
2102 // make cells at least 1 pixel wide to avoid singularities (division by zero)
2104 forEveryVisibleItem(&KTreeView::getMaxItemWidth
, &maxW
);
2105 maxItemWidth
= maxW
;
2109 int xoff
= xOffset();
2110 int yoff
= yOffset();
2111 if (xoff
> maxXOffset()) xoff
= maxXOffset();
2112 if (yoff
> maxYOffset()) yoff
= maxYOffset();
2114 setOffset(xoff
, yoff
);
2117 void KTreeView::updateVisibleItems()
2121 updateVisibleItemRec(treeRoot
, index
, count
);
2122 assert(index
== count
);
2127 void KTreeView::updateVisibleItemRec(KTreeViewItem
* item
, int& index
, int& count
)
2129 if (!item
->isExpanded()) {
2130 // no visible items if not expanded
2135 * Record the children of item in the list of visible items.
2137 * Don't register item itself, it's already in the list. Also only
2138 * allocate new space for children.
2140 count
+= item
->childCount();
2141 if (count
> itemCapacity
) {
2143 int newCapacity
= itemCapacity
;
2145 newCapacity
+= newCapacity
;
2146 } while (newCapacity
< count
);
2147 KTreeViewItem
** newItems
= new KTreeViewItem
*[newCapacity
];
2148 // clear the unneeded space
2149 for (int i
= index
; i
< newCapacity
; i
++) {
2152 // move already accumulated items over
2153 for (int i
= index
-1; i
>= 0; i
--) {
2154 newItems
[i
] = visibleItems
[i
];
2156 delete[] visibleItems
;
2157 visibleItems
= newItems
;
2158 itemCapacity
= newCapacity
;
2161 for (KTreeViewItem
* i
= item
->getChild(); i
!= 0; i
= i
->getSibling()) {
2162 visibleItems
[index
++] = i
;
2163 updateVisibleItemRec(i
, index
, count
);