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
);
627 setFocusPolicy(StrongFocus
);
628 treeRoot
= new KTreeViewItem
;
629 treeRoot
->setExpanded(true);
630 treeRoot
->owner
= this;
632 visibleItems
= new KTreeViewItem
*[itemCapacity
];
633 // clear those pointers
634 for (int j
= itemCapacity
-1; j
>= 0; j
--) {
640 KTreeView::~KTreeView()
644 delete[] visibleItems
;
648 // appends a child to the item at the given index with the given text
650 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
653 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
654 item
->setDeleteChildren(true);
655 appendChildItem(item
, index
);
658 // appends a child to the item at the end of the given path with
659 // the given text and pixmap
660 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
661 const KPath
& thePath
)
663 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
664 item
->setDeleteChildren(true);
665 appendChildItem(item
, thePath
);
668 // appends the given item to the children of the item at the given index
669 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, int index
)
671 /* find parent item and append new item to parent's sub tree */
672 KTreeViewItem
* parentItem
= itemAt(index
);
675 appendChildItem(parentItem
, newItem
);
678 // appends the given item to the children of the item at the end of the
680 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, const KPath
& thePath
)
682 /* find parent item and append new item to parent's sub tree */
683 KTreeViewItem
* parentItem
= itemAt(thePath
);
686 appendChildItem(parentItem
, newItem
);
689 // indicates whether horizontal scrollbar appears only when needed
690 bool KTreeView::autoBottomScrollBar() const
692 return testTableFlags(Tbl_autoHScrollBar
);
695 // indicates whether vertical scrollbar appears only when needed
696 bool KTreeView::autoScrollBar() const
698 return testTableFlags(Tbl_autoVScrollBar
);
701 // indicates whether display updates automatically on changes
702 bool KTreeView::autoUpdate() const
704 return QTableView::autoUpdate();
707 // indicates whether horizontal scrollbar is present
708 bool KTreeView::bottomScrollBar() const
710 return testTableFlags(Tbl_hScrollBar
);
713 // translate mouse coord to cell coord
714 QPoint
KTreeView::cellCoords(int row
, const QPoint
& widgetCoord
)
716 int cellX
= 0, cellY
= 0;
718 rowYPos(row
, &cellY
);
719 return QPoint(widgetCoord
.x() - cellX
, widgetCoord
.y() - cellY
);
722 // find item at specified index and change pixmap and/or text
723 void KTreeView::changeItem(const char *newText
,
724 const QPixmap
*newPixmap
,
727 KTreeViewItem
*item
= itemAt(index
);
729 changeItem(item
, index
, newText
, newPixmap
);
732 // find item at end of specified path, and change pixmap and/or text
733 void KTreeView::changeItem(const char* newText
,
734 const QPixmap
* newPixmap
,
735 const KPath
& thePath
)
737 KTreeViewItem
* item
= itemAt(thePath
);
739 int index
= itemRow(item
);
740 changeItem(item
, index
, newText
, newPixmap
);
744 // clear all items from list and erase display
745 void KTreeView::clear()
749 /* somewhat of a hack for takeItem so it doesn't update the current item... */
752 bool autoU
= autoUpdate();
753 setAutoUpdate(FALSE
);
754 QStack
<KTreeViewItem
> stack
;
755 stack
.push(treeRoot
);
756 while(!stack
.isEmpty()) {
757 KTreeViewItem
*item
= stack
.pop();
758 if(item
->hasChild()) {
760 stack
.push(item
->getChild());
762 else if(item
->hasSibling()) {
764 stack
.push(item
->getSibling());
766 else if(item
->getParent() != 0) {
772 if(goingDown
|| QApplication::closingDown())
774 setAutoUpdate(autoU
);
775 if(autoU
&& isVisible())
779 // return a count of all the items in the tree, whether visible or not
780 uint
KTreeView::count()
783 forEveryItem(&KTreeView::countItem
, (void *)&total
);
787 // returns the index of the current (highlighted) item
788 int KTreeView::currentItem() const
793 // collapses the item at the specified row index.
794 void KTreeView::collapseItem(int index
, bool emitSignal
)
796 KTreeViewItem
* item
= itemAt(index
);
798 collapseSubTree(item
, emitSignal
);
801 // expands the item at the specified row indes.
802 void KTreeView::expandItem(int index
, bool emitSignal
)
804 KTreeViewItem
* item
= itemAt(index
);
806 expandSubTree(item
, emitSignal
);
809 // returns the depth the tree is automatically expanded to when
811 int KTreeView::expandLevel() const
816 // visits every item in the tree, visible or not and applies
817 // the user supplied function with the item and user data passed as parameters
818 // if user supplied function returns true, traversal ends and function returns
819 bool KTreeView::forEveryItem(KForEveryFunc func
, void* user
, KTreeViewItem
* item
)
824 assert(item
->owner
== this);
825 item
= item
->getChild();
828 // visit the siblings
829 if ((*func
)(item
, user
)) {
832 // visit the children (recursively)
833 if (item
->hasChild()) {
834 if (forEveryItem(func
, user
, item
))
837 item
= item
->getSibling();
842 // visits every visible item in the tree in order and applies the
843 // user supplied function with the item and user data passed as parameters
844 // if user supplied function returns TRUE, traversal ends and function
846 bool KTreeView::forEveryVisibleItem(KForEveryFunc func
, void *user
,
852 // children are invisible (hence, nothing to do)
853 // if item is invisible or collapsed
854 if (!item
->isVisible() || !item
->isExpanded()) {
858 assert(item
->owner
== this);
859 item
= item
->getChild();
862 // visit the siblings
863 if ((*func
)(item
, user
)) {
866 // visit the children (recursively)
867 if (item
->hasChild() && item
->isExpanded()) {
868 if (forEveryVisibleItem(func
, user
, item
))
871 item
= item
->getSibling();
876 // returns a pointer to the KTreeViewItem at the current index
877 // or 0 if no current item
878 KTreeViewItem
*KTreeView::getCurrentItem()
880 if(current
== -1) return 0;
881 return itemAt(current
);
884 // returns the current indent spacing
885 int KTreeView::indentSpacing()
890 // inserts a new item with the specified text and pixmap before
891 // or after the item at the given index, depending on the value
893 // if index is negative, appends item to tree at root level
894 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
895 int row
, bool prefix
)
897 KTreeViewItem
* refItem
= itemAt(row
);
899 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
900 item
->setDeleteChildren(true);
902 bool success
= insertItem(refItem
, item
, prefix
);
908 // inserts a new item with the specified text and pixmap before
909 // or after the item at the end of the given path, depending on the value
911 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
912 const KPath
& path
, bool prefix
)
914 KTreeViewItem
* refItem
= itemAt(path
);
916 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
917 item
->setDeleteChildren(true);
919 bool success
= insertItem(refItem
, item
, prefix
);
925 // inserts the given item or derived object into the tree before
926 // or after the item at the given index, depending on the value
928 // if index is negative, appends item to tree at root level
929 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
930 int index
, bool prefix
)
932 // find the item currently at the index, if there is one
933 KTreeViewItem
* refItem
= itemAt(index
);
935 // insert new item at the appropriate place
936 return insertItem(refItem
, newItem
, prefix
);
939 // inserts the given item or derived object into the tree before
940 // or after the item at the end of the given path, depending on the value
942 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
943 const KPath
& thePath
, bool prefix
)
945 // find the item currently at the end of the path, if there is one
946 KTreeViewItem
* refItem
= itemAt(thePath
);
948 // insert new item at appropriate place
949 return insertItem(refItem
, newItem
, prefix
);
953 * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
956 KTreeViewItem
* KTreeView::itemAt(int row
)
958 if (row
< 0 || row
>= numRows()) {
962 // lookup the item in the list of visible items
963 assert(row
< itemCapacity
);
964 KTreeViewItem
* i
= visibleItems
[row
];
970 // returns pointer to KTreeViewItem at the end of the
971 // path or 0 if not found
972 KTreeViewItem
* KTreeView::itemAt(const KPath
& path
)
977 // need a copy of the path because recursiveFind will destroy it
979 pathCopy
.setAutoDelete(false);
982 return recursiveFind(pathCopy
);
985 // computes the path of the item at the specified index
986 // if index is invalid, nothing is done.
987 void KTreeView::itemPath(int row
, KPath
& path
)
989 KTreeViewItem
* item
= itemAt(row
);
991 itemPath(item
, path
);
995 // returns the row in the visible tree of the given item or
997 int KTreeView::itemRow(KTreeViewItem
* item
)
999 if (item
->owner
== this) {
1000 // search in list of visible items
1001 for (int i
= numRows()-1; i
>= 0; i
--) {
1002 if (visibleItems
[i
] == item
) {
1012 * move the subtree at the specified index up one branch level (make root
1013 * item a sibling of its current parent)
1015 void KTreeView::join(int index
)
1017 KTreeViewItem
*item
= itemAt(index
);
1023 * move the subtree at the specified index up one branch level (make root
1024 * item a sibling of it's current parent)
1026 void KTreeView::join(const KPath
& path
)
1028 KTreeViewItem
*item
= itemAt(path
);
1033 /* move item at specified index one slot down in its parent's sub tree */
1034 void KTreeView::lowerItem(int index
)
1036 KTreeViewItem
*item
= itemAt(index
);
1041 /* move item at specified path one slot down in its parent's sub tree */
1042 void KTreeView::lowerItem(const KPath
& path
)
1044 KTreeViewItem
* item
= itemAt(path
);
1049 /* move item at specified index one slot up in its parent's sub tree */
1050 void KTreeView::raiseItem(int index
)
1052 KTreeViewItem
* item
= itemAt(index
);
1057 /* move item at specified path one slot up in its parent's sub tree */
1058 void KTreeView::raiseItem(const KPath
& path
)
1060 KTreeViewItem
* item
= itemAt(path
);
1065 // remove the item at the specified index and delete it
1066 void KTreeView::removeItem(int index
)
1068 KTreeViewItem
*item
= itemAt(index
);
1075 // remove the item at the end of the specified path and delete it
1076 void KTreeView::removeItem(const KPath
& thePath
)
1078 KTreeViewItem
* item
= itemAt(thePath
);
1085 // indicates whether vertical scrollbar is present
1086 bool KTreeView::scrollBar() const
1088 return testTableFlags(Tbl_vScrollBar
);
1091 void KTreeView::scrollVisible(KTreeViewItem
* item
, bool children
)
1095 int row
= itemRow(item
);
1097 return; /* do nothing if invisible */
1099 if (children
&& item
->isExpanded()) {
1100 // we are concerned about children
1101 if (!rowIsVisible(row
)) {
1102 // just move to the top
1105 // this is the complicated part
1106 // count the visible children (including grandchildren)
1108 forEveryVisibleItem(countItem
, &numVisible
, item
);
1109 // if the last child is visible, do nothing
1110 if (rowIsVisible(row
+ numVisible
))
1113 * Basically, item will become the top cell; but if there are
1114 * more visible rows in the widget than we have children, then
1115 * we don't move that far.
1117 int remain
= lastRowVisible()-topCell()-numVisible
;
1121 setTopCell(QMAX(0,row
-remain
));
1125 // we are not concerned about children
1126 if (rowIsVisible(row
))
1128 // just move the item to the top
1133 // enables/disables auto update of display
1134 void KTreeView::setAutoUpdate(bool enable
)
1136 QTableView::setAutoUpdate(enable
);
1139 // enables/disables horizontal scrollbar
1140 void KTreeView::setBottomScrollBar(bool enable
)
1142 enable
? setTableFlags(Tbl_hScrollBar
) :
1143 clearTableFlags(Tbl_hScrollBar
);
1146 // sets the current item and hightlights it, emitting signals
1147 void KTreeView::setCurrentItem(int row
)
1151 int numVisible
= numRows();
1152 if (row
> numVisible
)
1154 int oldCurrent
= current
;
1156 if (oldCurrent
< numVisible
)
1157 updateCell(oldCurrent
, 0);
1159 updateCell(current
, 0, false);
1160 emit
highlighted(current
);
1164 // enables/disables drawing of expand button
1165 void KTreeView::setExpandButtonDrawing(bool enable
)
1167 if (drawExpandButton
== enable
)
1169 drawExpandButton
= enable
;
1171 // the user parameter is cast to a bool in setItemExpandButtonDrawing
1172 forEveryItem(&KTreeView::setItemExpandButtonDrawing
, enable
? &enable
: 0);
1174 if (autoUpdate() && isVisible())
1178 // sets depth to which subtrees are automatically expanded, and
1179 // redraws tree if auto update enabled
1180 void KTreeView::setExpandLevel(int level
)
1182 if (expansion
== level
)
1185 KTreeViewItem
* item
= getCurrentItem();
1186 forEveryItem(&KTreeView::setItemExpandLevel
, 0);
1188 if (item
->getParent()->isExpanded())
1190 item
= item
->getParent();
1193 setCurrentItem(itemRow(item
));
1194 if (autoUpdate() && isVisible())
1198 // sets the indent margin for all branches and repaints if auto update enabled
1199 void KTreeView::setIndentSpacing(int spacing
)
1201 if (itemIndent
== spacing
)
1203 itemIndent
= spacing
;
1205 if (autoUpdate() && isVisible())
1209 void KTreeView::setMoveCurrentToSibling(bool m
)
1211 moveCurrentToSibling
= m
;
1214 // enables/disables vertical scrollbar
1215 void KTreeView::setScrollBar(bool enable
)
1217 enable
? setTableFlags(Tbl_vScrollBar
) :
1218 clearTableFlags(Tbl_vScrollBar
);
1221 // enables/disables display of item text (keys)
1222 void KTreeView::setShowItemText(bool enable
)
1224 if (showText
== enable
)
1228 // the user parameter is cast to a bool in setItemShowText
1229 forEveryItem(&KTreeView::setItemShowText
, enable
? &enable
: 0);
1231 if (autoUpdate() && isVisible())
1235 // indicates whether vertical scrolling is by pixel or row
1236 void KTreeView::setSmoothScrolling(bool enable
)
1238 enable
? setTableFlags(Tbl_smoothVScrolling
) :
1239 clearTableFlags(Tbl_smoothVScrolling
);
1242 // enables/disables tree branch drawing
1243 void KTreeView::setTreeDrawing(bool enable
)
1245 if (drawTree
== enable
)
1249 // the user parameter is cast to a bool in setItemTreeDrawing
1250 forEveryItem(&KTreeView::setItemTreeDrawing
, enable
? &enable
: 0);
1252 if (autoUpdate() && isVisible())
1256 // indicates whether item text keys are displayed
1257 bool KTreeView::showItemText() const
1262 // indicates whether scrolling is by pixel or row
1263 bool KTreeView::smoothScrolling() const
1265 return testTableFlags(Tbl_smoothVScrolling
);
1268 // indents the item at the given index, splitting the tree into
1270 void KTreeView::split(int index
)
1272 KTreeViewItem
*item
= itemAt(index
);
1277 // indents the item at the given path, splitting the tree into
1279 void KTreeView::split(const KPath
& path
)
1281 KTreeViewItem
* item
= itemAt(path
);
1286 // removes item at specified index from tree but does not delete it
1287 // returns pointer to the item or 0 if not succesful
1288 KTreeViewItem
*KTreeView::takeItem(int index
)
1290 KTreeViewItem
*item
= itemAt(index
);
1296 // removes item at specified path from tree but does not delete it
1297 // returns pointer to the item or 0 if not successful
1298 KTreeViewItem
* KTreeView::takeItem(const KPath
& path
)
1300 KTreeViewItem
* item
= itemAt(path
);
1306 // indicates whether tree branches are drawn
1307 bool KTreeView::treeDrawing() const
1313 // appends a child to the specified parent item (note: a child, not a sibling, is added!)
1314 void KTreeView::appendChildItem(KTreeViewItem
* theParent
,
1315 KTreeViewItem
* newItem
)
1317 theParent
->appendChild(newItem
);
1320 newItem
->setDrawExpandButton(drawExpandButton
);
1321 newItem
->setDrawTree(drawTree
);
1322 newItem
->setDrawText(showText
);
1323 if (level(newItem
) < expansion
) {
1324 newItem
->setExpanded(true);
1327 // fix up branch levels of any children that the new item may already have
1328 if(newItem
->hasChild()) {
1329 fixChildren(newItem
);
1332 // if necessary, adjust cell width, number of rows and repaint
1333 if (newItem
->isVisible() || theParent
->childCount() == 1) {
1334 bool autoU
= autoUpdate();
1335 setAutoUpdate(false);
1336 updateVisibleItems();
1337 setAutoUpdate(autoU
);
1338 if (autoU
&& isVisible())
1343 // returns the height of the cell(row) at the specified row (index)
1344 int KTreeView::cellHeight(int row
)
1346 return itemAt(row
)->height(fontMetrics());
1349 // returns the width of the cells. Note: this is mostly for derived classes
1350 // which have more than 1 column
1351 int KTreeView::cellWidth(int /*col*/)
1353 return maxItemWidth
;
1356 // changes the given item with the new text and/or pixmap
1357 void KTreeView::changeItem(KTreeViewItem
* toChange
, int itemRow
,
1358 const char* newText
, const QPixmap
* newPixmap
)
1360 int indent
= indentation(toChange
);
1361 int oldWidth
= toChange
->width(indent
);
1363 toChange
->setText(newText
);
1365 toChange
->setPixmap(*newPixmap
);
1366 if(oldWidth
!= toChange
->width(indent
))
1370 if(autoUpdate() && rowIsVisible(itemRow
))
1371 updateCell(itemRow
, 0);
1374 // collapses the subtree at the specified item
1375 void KTreeView::collapseSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1377 assert(subRoot
->owner
== this);
1378 if (!subRoot
->isExpanded())
1381 // must move the current item if it is visible
1382 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1384 subRoot
->setExpanded(false);
1385 if (subRoot
->isVisible()) {
1386 bool autoU
= autoUpdate();
1387 setAutoUpdate(false);
1388 updateVisibleItems();
1389 // re-seat current item
1391 setCurrentItem(itemRow(cur
));
1394 emit
collapsed(itemRow(subRoot
));
1396 setAutoUpdate(autoU
);
1397 if (autoU
&& isVisible())
1402 // used by count() with forEach() function to count total number
1403 // of items in the tree
1404 bool KTreeView::countItem(KTreeViewItem
*, void* total
)
1406 int* t
= static_cast<int*>(total
);
1411 // expands the subtree at the given item
1412 void KTreeView::expandSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1414 assert(subRoot
->owner
== this);
1415 if (subRoot
->isExpanded())
1418 // must move the current item if it is visible
1419 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1423 if (subRoot
->delayedExpanding
) {
1424 emit
expanding(subRoot
, allow
);
1429 subRoot
->setExpanded(true);
1431 if (subRoot
->isVisible()) {
1432 bool autoU
= autoUpdate();
1433 setAutoUpdate(false);
1434 updateVisibleItems();
1435 // re-seat current item
1437 setCurrentItem(itemRow(cur
));
1440 emit
expanded(itemRow(subRoot
));
1442 setAutoUpdate(autoU
);
1443 if (autoU
&& isVisible())
1448 // fix up branch levels out of whack from split/join operations on the tree
1449 void KTreeView::fixChildren(KTreeViewItem
*parentItem
)
1451 KTreeViewItem
* childItem
= 0;
1452 KTreeViewItem
* siblingItem
= 0;
1453 // int childBranch = parentItem->getBranch() + 1;
1454 if(parentItem
->hasChild()) {
1455 childItem
= parentItem
->getChild();
1456 // childItem->setBranch(childBranch);
1457 childItem
->owner
= parentItem
->owner
;
1458 fixChildren(childItem
);
1460 while(childItem
&& childItem
->hasSibling()) {
1461 siblingItem
= childItem
->getSibling();
1462 // siblingItem->setBranch(childBranch);
1463 siblingItem
->owner
= parentItem
->owner
;
1464 fixChildren(siblingItem
);
1465 childItem
= siblingItem
;
1470 * Handle QFocusEvent processing by setting current item to top row if
1471 * there is no current item, and updates cell to add or delete the focus
1472 * rectangle on the highlight bar. The base class is not called because it
1473 * does a repaint() which causes flicker.
1475 void KTreeView::focusInEvent(QFocusEvent
*)
1477 if (current
< 0 && numRows() > 0)
1478 setCurrentItem(topCell());
1479 updateCell(current
, 0);
1482 void KTreeView::focusOutEvent(QFocusEvent
*)
1484 updateCell(current
, 0);
1487 // called by updateCellWidth() for each item in the visible list
1488 bool KTreeView::getMaxItemWidth(KTreeViewItem
* item
, void* user
)
1490 assert(item
->owner
!= 0);
1491 int indent
= item
->owner
->indentation(item
);
1492 int* maxW
= static_cast<int*>(user
);
1493 int w
= item
->width(indent
);
1499 int KTreeView::indentation(KTreeViewItem
* item
) const
1501 return level(item
) * itemIndent
+ itemIndent
+ 3;
1504 // inserts the new item before or after the reference item, depending
1505 // on the value of prefix
1506 bool KTreeView::insertItem(KTreeViewItem
* referenceItem
,
1507 KTreeViewItem
* newItem
,
1510 assert(newItem
!= 0);
1511 assert(referenceItem
== 0 || referenceItem
->owner
== this);
1513 /* set the new item's state */
1514 newItem
->setDrawExpandButton(drawExpandButton
);
1515 newItem
->setDrawTree(drawTree
);
1516 newItem
->setDrawText(showText
);
1517 KTreeViewItem
* parentItem
;
1518 if (referenceItem
) {
1519 parentItem
= referenceItem
->getParent();
1520 int insertIndex
= parentItem
->childIndex(referenceItem
);
1523 parentItem
->insertChild(insertIndex
, newItem
);
1526 // no reference item, append at end of visible tree
1528 parentItem
= treeRoot
;
1529 parentItem
->appendChild(newItem
);
1532 // set item expansion
1533 if (level(newItem
) < expansion
)
1534 newItem
->setExpanded(true);
1536 // fix up branch levels of any children
1537 if (newItem
->hasChild())
1538 fixChildren(newItem
);
1540 // if repaint necessary, do it if visible and auto update
1542 if (newItem
->isVisible() || parentItem
->childCount() == 1) {
1543 bool autoU
= autoUpdate();
1544 setAutoUpdate(FALSE
);
1545 updateVisibleItems();
1546 setAutoUpdate(autoU
);
1547 if (autoU
&& isVisible())
1554 * returns pointer to item's path
1556 void KTreeView::itemPath(KTreeViewItem
* item
, KPath
& path
) const
1559 assert(item
->owner
== this);
1560 if (item
!= treeRoot
) {
1561 itemPath(item
->getParent(), path
);
1562 path
.push(new QString(item
->getText()));
1567 * joins the item's branch into the tree, making the item a sibling of its
1570 void KTreeView::join(KTreeViewItem
*item
)
1572 KTreeViewItem
*itemParent
= item
->getParent();
1573 if(itemParent
->hasParent()) {
1574 bool autoU
= autoUpdate();
1575 setAutoUpdate(FALSE
);
1577 insertItem(itemParent
, item
, FALSE
);
1578 setAutoUpdate(autoU
);
1579 if(autoU
&& isVisible())
1584 // handles keyboard interface
1585 void KTreeView::keyPressEvent(QKeyEvent
* e
)
1588 return; /* nothing to do */
1590 /* if there's no current item, make the top item current */
1591 if (currentItem() < 0)
1592 setCurrentItem(topCell());
1593 assert(currentItem() >= 0); /* we need a current item */
1594 assert(itemAt(currentItem()) != 0); /* we really need a current item */
1596 // give currentItem a chance to handle the event
1597 if (itemAt(currentItem())->keyEvent(e
))
1598 return; /* handled */
1600 int pageSize
, delta
;
1601 KTreeViewItem
* item
;
1606 // make previous item current, scroll up if necessary
1607 if (currentItem() > 0) {
1608 setCurrentItem(currentItem() - 1);
1609 scrollVisible(itemAt(currentItem()), false);
1613 // make next item current, scroll down if necessary
1614 if (currentItem() < numRows() - 1) {
1615 setCurrentItem(currentItem() + 1);
1616 if (currentItem() > lastRowVisible()) {
1617 // scrollVisible is not feasible here because
1618 // it scrolls the item to the top
1619 setTopCell(topCell() + currentItem() - lastRowVisible());
1620 } else if (currentItem() < topCell()) {
1621 setTopCell(currentItem());
1626 // move highlight one page down and scroll down
1627 delta
= currentItem() - topCell();
1628 pageSize
= lastRowVisible() - topCell();
1629 setTopCell(QMIN(topCell() + pageSize
, numRows() - 1));
1630 setCurrentItem(QMIN(topCell() + delta
, numRows() - 1));
1633 // move highlight one page up and scroll up
1634 delta
= currentItem() - topCell();
1635 pageSize
= lastRowVisible() - topCell();
1636 setTopCell(QMAX(topCell() - pageSize
, 0));
1637 setCurrentItem(QMAX(topCell() + delta
, 0));
1641 // if current item has subtree and is collapsed, expand it
1642 item
= itemAt(currentItem());
1643 if (item
->isExpanded() && item
->hasChild() && key
== Key_Right
) {
1644 // going right on an expanded item is like going down
1648 expandSubTree(item
, true);
1649 scrollVisible(item
, true);
1654 // if current item has subtree and is expanded, collapse it
1655 item
= itemAt(currentItem());
1656 if ((!item
->isExpanded() || !item
->hasChild()) && key
== Key_Left
) {
1657 // going left on a collapsed item goes to its parent
1658 item
= item
->getParent();
1659 if (item
== treeRoot
)
1660 break; /* we're already at the top */
1661 assert(item
->isVisible());
1662 setCurrentItem(itemRow(item
));
1664 collapseSubTree(item
, true);
1666 scrollVisible(item
, false);
1670 // select the current item
1671 if (currentItem() >= 0)
1672 emit
selected(currentItem());
1679 // handles keyboard interface
1680 void KTreeView::keyReleaseEvent(QKeyEvent
* e
)
1682 if (currentItem() >= 0 && itemAt(currentItem()) != 0)
1683 itemAt(currentItem())->keyEvent(e
);
1686 int KTreeView::level(KTreeViewItem
* item
) const
1689 assert(item
->owner
== this);
1690 assert(item
!= treeRoot
);
1692 item
= item
->parent
->parent
; /* since item != treeRoot, there is a parent */
1694 item
= item
->parent
;
1700 /* move specified item down one slot in parent's subtree */
1701 void KTreeView::lowerItem(KTreeViewItem
*item
)
1703 KTreeViewItem
*itemParent
= item
->getParent();
1704 uint itemChildIndex
= itemParent
->childIndex(item
);
1705 if(itemChildIndex
< itemParent
->childCount() - 1) {
1706 bool autoU
= autoUpdate();
1707 setAutoUpdate(FALSE
);
1709 insertItem(itemParent
->childAt(itemChildIndex
), item
, FALSE
);
1710 setAutoUpdate(autoU
);
1711 if(autoU
&& isVisible())
1716 // handle mouse double click events by selecting the clicked item
1717 // and emitting the signal
1718 void KTreeView::mouseDoubleClickEvent(QMouseEvent
* e
)
1720 // find out which row has been clicked
1721 int itemClicked
= findRow(e
->y());
1723 if (itemClicked
< 0)
1724 return; /* invalid row, do nothing */
1726 KTreeViewItem
* item
= itemAt(itemClicked
);
1730 // translate mouse coord to cell coord
1731 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1734 if (item
->mouseEvent(e
, cellCoord
))
1738 int indent
= indentation(item
);
1739 if (item
->boundingRect(indent
).contains(cellCoord
))
1740 emit
selected(itemClicked
);
1743 // handle mouse movement events
1744 void KTreeView::mouseMoveEvent(QMouseEvent
* e
)
1746 // in rubberband_mode we actually scroll the window now
1747 if (rubberband_mode
) {
1748 move_rubberband(e
->pos());
1750 // else forward to current item
1751 int current
= currentItem();
1752 if (current
>= 0 && itemAt(current
))
1753 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1758 // handle single mouse presses
1759 void KTreeView::mousePressEvent(QMouseEvent
* e
)
1761 /* first: cancel rubberbanding if it's on */
1762 if (rubberband_mode
)
1764 // another button was pressed while rubberbanding, stop the move.
1765 // RB: if we allow other buttons while rubberbanding the tree can expand
1766 // while rubberbanding - we then need to recalculate and resize the
1767 // rubberband rect and show the new size
1772 // find out which row has been clicked
1773 int itemClicked
= findRow(e
->y());
1775 // nothing to do if not on valid row
1776 if (itemClicked
< 0)
1778 KTreeViewItem
* item
= itemAt(itemClicked
);
1782 // translate mouse coord to cell coord
1783 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1785 // give the item a crack
1786 if (item
->mouseEvent(e
, cellCoord
))
1787 return; /* event eaten by item */
1789 // check for rubberbanding
1790 if (e
->button() == MidButton
)
1792 // RB: the MMB is hardcoded to the "rubberband" scroll mode
1793 if (!rubberband_mode
) {
1794 start_rubberband(e
->pos());
1799 if (e
->button() == RightButton
) {
1800 emit
rightPressed(itemClicked
, e
->pos());
1802 /* hit test expand button (doesn't set currentItem) */
1803 else if (item
->expandButtonClicked(cellCoord
)) {
1804 if (item
->isExpanded()) {
1805 collapseSubTree(item
, true);
1807 expandSubTree(item
, true);
1808 scrollVisible(item
, true); /* make children visible */
1812 else if (item
->boundingRect(indentation(item
)).contains(cellCoord
)) {
1813 setCurrentItem(itemClicked
);
1817 // handle mouse release events
1818 void KTreeView::mouseReleaseEvent(QMouseEvent
*e
)
1820 /* if it's the MMB end rubberbanding */
1821 if (rubberband_mode
) {
1822 if (e
->button() == MidButton
)
1826 // forward to current item
1827 int current
= currentItem();
1828 if (current
>= 0 && itemAt(current
))
1829 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1832 // rubberband move: draw the rubberband
1833 void KTreeView::draw_rubberband()
1836 * RB: I'm using a white pen because of the XorROP mode. I would prefer
1837 * to draw the rectangle in red but I don't now how to get a pen which
1838 * draws red in XorROP mode (this depends on the background). In fact
1839 * the color should be configurable.
1842 if (!rubberband_mode
) return;
1843 QPainter
paint(this);
1844 paint
.setPen(white
);
1845 paint
.setRasterOp(XorROP
);
1846 paint
.drawRect(xOffset()*viewWidth()/totalWidth(),
1847 yOffset()*viewHeight()/totalHeight(),
1848 rubber_width
+1, rubber_height
+1);
1852 // rubberband move: start move
1853 void KTreeView::start_rubberband(const QPoint
& where
)
1855 if (rubberband_mode
) { // Oops!
1858 /* RB: Don't now, if this check is necessary */
1859 if (!viewWidth() || !viewHeight()) return;
1860 if (!totalWidth() || !totalHeight()) return;
1862 // calculate the size of the rubberband rectangle
1863 rubber_width
= viewWidth()*viewWidth()/totalWidth();
1864 if (rubber_width
> viewWidth()) rubber_width
= viewWidth();
1865 rubber_height
= viewHeight()*viewHeight()/totalHeight();
1866 if (rubber_height
> viewHeight()) rubber_height
= viewHeight();
1868 // remember the cursor position and the actual offset
1869 rubber_startMouse
= where
;
1870 rubber_startX
= xOffset();
1871 rubber_startY
= yOffset();
1872 rubberband_mode
=TRUE
;
1876 // rubberband move: end move
1877 void KTreeView::end_rubberband()
1879 if (!rubberband_mode
) return;
1881 rubberband_mode
= FALSE
;
1884 // rubberband move: hanlde mouse moves
1885 void KTreeView::move_rubberband(const QPoint
& where
)
1887 if (!rubberband_mode
) return;
1889 // look how much the mouse moved and calc the new scroll position
1890 QPoint delta
= where
- rubber_startMouse
;
1891 int nx
= rubber_startX
+ delta
.x() * totalWidth() / viewWidth();
1892 int ny
= rubber_startY
+ delta
.y() * totalHeight() / viewHeight();
1894 // check the new position (and make it valid)
1896 else if (nx
> maxXOffset()) nx
= maxXOffset();
1898 else if (ny
> maxYOffset()) ny
= maxYOffset();
1900 // redraw the rubberband at the new position
1907 // paints the cell at the specified row and col
1908 // col is ignored for now since there is only one
1909 void KTreeView::paintCell(QPainter
* p
, int row
, int)
1911 KTreeViewItem
* item
= itemAt(row
);
1915 QColorGroup cg
= colorGroup();
1916 int indent
= indentation(item
);
1917 item
->paint(p
, indent
, cg
,
1918 current
== row
); /* highlighted */
1922 /* This is needed to make the kcontrol's color setup working (Marcin Dalecki) */
1923 void KTreeView::paletteChange(const QPalette
&)
1925 setBackgroundColor(colorGroup().base());
1930 /* raise the specified item up one slot in parent's subtree */
1931 void KTreeView::raiseItem(KTreeViewItem
*item
)
1933 KTreeViewItem
*itemParent
= item
->getParent();
1934 int itemChildIndex
= itemParent
->childIndex(item
);
1935 if(itemChildIndex
> 0) {
1936 bool autoU
= autoUpdate();
1937 setAutoUpdate(FALSE
);
1939 insertItem(itemParent
->childAt(--itemChildIndex
), item
, TRUE
);
1940 setAutoUpdate(autoU
);
1941 if(autoU
&& isVisible())
1946 // find the item at the path
1947 KTreeViewItem
* KTreeView::recursiveFind(KPath
& path
)
1953 QString
* searchString
= path
.pop();
1955 // find the parent item
1956 KTreeViewItem
* parent
= recursiveFind(path
);
1961 * Iterate through the parent's children searching for searchString.
1963 KTreeViewItem
* sibling
= parent
->getChild();
1964 while (sibling
!= 0) {
1965 if (*searchString
== sibling
->getText()) {
1966 break; /* found it! */
1968 sibling
= sibling
->getSibling();
1973 void KTreeView::setItemExpanded(KTreeViewItem
* item
)
1975 if (level(item
) < expansion
) {
1976 expandSubTree(item
, true);
1978 collapseSubTree(item
, true);
1982 // called by setExpandLevel for each item in tree
1983 bool KTreeView::setItemExpandLevel(KTreeViewItem
* item
, void*)
1985 assert(item
->owner
!= 0);
1986 item
->owner
->setItemExpanded(item
);
1990 // called by setExpandButtonDrawing for every item in tree
1991 // the parameter drawButton is used as (and implicitly cast to) a bool
1992 bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem
* item
,
1995 item
->setDrawExpandButton(drawButton
);
1999 // called by setShowItemText for every item in tree
2000 // the parameter newDrawText is used as (and implicitly cast to) a bool
2001 bool KTreeView::setItemShowText(KTreeViewItem
* item
,
2004 item
->setDrawText(newDrawText
);
2008 // called by setTreeDrawing for every item in tree
2009 // the parameter drawTree is used as (and implicitly cast to) a bool
2010 bool KTreeView::setItemTreeDrawing(KTreeViewItem
* item
, void* drawTree
)
2012 item
->setDrawTree(drawTree
);
2016 // makes the item a child of the item above it, splitting
2017 // the tree into a new branch
2018 void KTreeView::split(KTreeViewItem
*item
)
2020 KTreeViewItem
*itemParent
= item
->getParent();
2021 int itemChildIndex
= itemParent
->childIndex(item
);
2022 if(itemChildIndex
== 0)
2024 bool autoU
= autoUpdate();
2025 setAutoUpdate(FALSE
);
2027 appendChildItem(itemParent
->childAt(--itemChildIndex
), item
);
2028 setAutoUpdate(autoU
);
2029 if(autoU
&& isVisible())
2033 // removes the item from the tree without deleting it
2034 void KTreeView::takeItem(KTreeViewItem
* item
)
2036 assert(item
->owner
== this);
2038 // TODO: go over this function again
2040 bool wasVisible
= item
->isVisible();
2042 * If we have a current item, make sure that it is not in the subtree
2043 * that we are about to remove. If the current item is in the part
2044 * below the taken-out subtree, we must move it up a number of rows if
2045 * the taken-out subtree is at least partially visible.
2047 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
2048 KTreeViewItem
* oldCurrent
= cur
;
2049 if (wasVisible
&& cur
!= 0) {
2050 KTreeViewItem
* c
= cur
;
2051 while (c
!= 0 && c
!= item
) {
2055 // move current item to parent
2056 cur
= item
->getParent();
2057 if (cur
== treeRoot
) {
2059 // move it to next or previous sibling
2060 if (moveCurrentToSibling
) {
2061 if (item
->getSibling() != 0) {
2062 cur
= item
->getSibling();
2063 } else if (treeRoot
->getChild() != item
) {
2064 cur
= treeRoot
->getChild();
2065 while (cur
!= 0 && cur
->getSibling() != item
)
2066 cur
= cur
->getSibling();
2072 KTreeViewItem
* parentItem
= item
->getParent();
2073 parentItem
->removeChild(item
);
2075 if (wasVisible
|| parentItem
->childCount() == 0) {
2076 bool autoU
= autoUpdate();
2077 setAutoUpdate(FALSE
);
2078 updateVisibleItems();
2079 setAutoUpdate(autoU
);
2080 if (autoU
&& isVisible())
2084 // re-seat the current item
2085 // row changes if cur is below the taken item
2086 current
= cur
!= 0 ? itemRow(cur
) : -1;
2087 // signal must be emitted only if item really changed
2088 if (cur
!= oldCurrent
) {
2089 updateCell(current
, 0, false);
2090 emit
highlighted(current
);
2094 // visits each item, calculates the maximum width
2095 // and updates QTableView
2096 void KTreeView::updateCellWidth()
2098 // make cells at least 1 pixel wide to avoid singularities (division by zero)
2100 forEveryVisibleItem(&KTreeView::getMaxItemWidth
, &maxW
);
2101 maxItemWidth
= maxW
;
2105 int xoff
= xOffset();
2106 int yoff
= yOffset();
2107 if (xoff
> maxXOffset()) xoff
= maxXOffset();
2108 if (yoff
> maxYOffset()) yoff
= maxYOffset();
2110 setOffset(xoff
, yoff
);
2113 void KTreeView::updateVisibleItems()
2117 updateVisibleItemRec(treeRoot
, index
, count
);
2118 assert(index
== count
);
2123 void KTreeView::updateVisibleItemRec(KTreeViewItem
* item
, int& index
, int& count
)
2125 if (!item
->isExpanded()) {
2126 // no visible items if not expanded
2131 * Record the children of item in the list of visible items.
2133 * Don't register item itself, it's already in the list. Also only
2134 * allocate new space for children.
2136 count
+= item
->childCount();
2137 if (count
> itemCapacity
) {
2139 int newCapacity
= itemCapacity
;
2141 newCapacity
+= newCapacity
;
2142 } while (newCapacity
< count
);
2143 KTreeViewItem
** newItems
= new KTreeViewItem
*[newCapacity
];
2144 // clear the unneeded space
2145 for (int i
= index
; i
< newCapacity
; i
++) {
2148 // move already accumulated items over
2149 for (int i
= index
-1; i
>= 0; i
--) {
2150 newItems
[i
] = visibleItems
[i
];
2152 delete[] visibleItems
;
2153 visibleItems
= newItems
;
2154 itemCapacity
= newCapacity
;
2157 for (KTreeViewItem
* i
= item
->getChild(); i
!= 0; i
= i
->getSibling()) {
2158 visibleItems
[index
++] = i
;
2159 updateVisibleItemRec(i
, index
, count
);