ctkTreeComboBox.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. All rights reserved.
  5. Distributed under a BSD License. See LICENSE.txt file.
  6. This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
  7. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the above copyright notice for more information.
  9. =========================================================================*/
  10. // Qt includes
  11. #include <QEvent>
  12. #include <QMouseEvent>
  13. #include <QModelIndex>
  14. #include <QTreeView>
  15. #include <QDebug>
  16. // CTK includes
  17. #include "ctkTreeComboBox.h"
  18. // -------------------------------------------------------------------------
  19. class ctkTreeComboBoxPrivate: public ctkPrivate<ctkTreeComboBox>
  20. {
  21. public:
  22. bool SkipNextHide;
  23. bool ResetPopupSize;
  24. void init()
  25. {
  26. this->SkipNextHide = false;
  27. this->ResetPopupSize = false;
  28. }
  29. };
  30. // -------------------------------------------------------------------------
  31. ctkTreeComboBox::ctkTreeComboBox(QWidget* _parent):Superclass(_parent)
  32. {
  33. CTK_INIT_PRIVATE(ctkTreeComboBox);
  34. CTK_D(ctkTreeComboBox);
  35. d->init();
  36. QTreeView* treeView = new QTreeView(this);
  37. treeView->setHeaderHidden(true);
  38. this->setView(treeView);
  39. // we install the filter AFTER the QComboBox installed it.
  40. // so that our eventFilter will be called first
  41. this->view()->viewport()->installEventFilter(this);
  42. connect(treeView, SIGNAL(collapsed(const QModelIndex&)),
  43. this, SLOT(onCollapsed(const QModelIndex&)));
  44. connect(treeView, SIGNAL(expanded(const QModelIndex&)),
  45. this, SLOT(onExpanded(const QModelIndex&)));
  46. }
  47. // -------------------------------------------------------------------------
  48. bool ctkTreeComboBox::eventFilter(QObject* object, QEvent* _event)
  49. {
  50. CTK_D(ctkTreeComboBox);
  51. bool res = false;
  52. if (_event->type() == QEvent::MouseButtonRelease &&
  53. object == this->view()->viewport())
  54. {
  55. QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(_event);
  56. QModelIndex index = this->view()->indexAt(mouseEvent->pos());
  57. // do we click the branch (+ or -) or the item itself ?
  58. if (this->view()->model()->hasChildren(index) &&
  59. (index.flags() & Qt::ItemIsSelectable) &&
  60. !this->view()->visualRect(index).contains(mouseEvent->pos()))
  61. {//qDebug() << "Set skip on";
  62. // if the branch is clicked, then we don't want to close the
  63. // popup. (we don't want to select the item, just expand it.)
  64. // of course, all that doesn't apply with unselectable items, as
  65. // they won't close the popup.
  66. d->SkipNextHide = true;
  67. }
  68. // we want to get rid of an odd behavior.
  69. // If the user highlight a selectable item and then
  70. // click on the branch of an unselectable item while keeping the
  71. // previous selection. The popup would be normally closed in that
  72. // case. We don't want that.
  73. if ( this->view()->model()->hasChildren(index) &&
  74. !(index.flags() & Qt::ItemIsSelectable) &&
  75. !this->view()->visualRect(index).contains(mouseEvent->pos()))
  76. {//qDebug() << "eat";
  77. // eat the event, don't go to the QComboBox event filters.
  78. res = true;
  79. }
  80. if (d->ResetPopupSize)
  81. {
  82. d->ResetPopupSize = false;
  83. //this->QComboBox::showPopup();
  84. }
  85. }
  86. return res;
  87. }
  88. // -------------------------------------------------------------------------
  89. void ctkTreeComboBox::showPopup()
  90. {
  91. this->setRootModelIndex(QModelIndex());
  92. this->QComboBox::showPopup();
  93. }
  94. // -------------------------------------------------------------------------
  95. void ctkTreeComboBox::hidePopup()
  96. {
  97. CTK_D(ctkTreeComboBox);
  98. if (d->SkipNextHide)
  99. {// don't hide the popup if the selected item is a parent.
  100. d->SkipNextHide = false;
  101. //this->setCurrentIndex(-1);
  102. //qDebug() << "skip";
  103. //this->QComboBox::showPopup();
  104. }
  105. else
  106. {
  107. QModelIndex _currentIndex = this->view()->currentIndex();
  108. //qDebug() << "ctkTreeComboBox::hidePopup() " << _currentIndex << " " << _currentIndex.row();
  109. //qDebug() << "before: " << this->currentIndex() << this->view()->currentIndex();
  110. this->QComboBox::hidePopup();
  111. //qDebug() << "after: " << this->currentIndex() << this->view()->currentIndex();
  112. this->setRootModelIndex(_currentIndex.parent());
  113. this->setCurrentIndex(_currentIndex.row());
  114. //qDebug() << "after2: " << this->currentIndex() << this->view()->currentIndex();
  115. }
  116. }
  117. // -------------------------------------------------------------------------
  118. void ctkTreeComboBox::onCollapsed(const QModelIndex& index)
  119. {
  120. CTK_D(ctkTreeComboBox);
  121. if (this->view()->currentIndex().parent() == index)
  122. {
  123. // in the case the current item is a child of the collapsed/expanded item.
  124. // we don't want to resize the popup as it would undo the collapsed item.
  125. return;
  126. }
  127. d->ResetPopupSize = true;
  128. }
  129. // -------------------------------------------------------------------------
  130. void ctkTreeComboBox::onExpanded(const QModelIndex& /*index*/)
  131. {
  132. ctk_d()->ResetPopupSize = true;
  133. }
  134. // -------------------------------------------------------------------------
  135. void ctkTreeComboBox::paintEvent(QPaintEvent *p)
  136. {
  137. //qDebug() << __FUNCTION__ << " " << this->currentText() << " " << this->currentIndex() ;
  138. //qDebug() << this->itemText(0) << this->itemText(1);
  139. this->QComboBox::paintEvent(p);
  140. }