ctkCheckableComboBox.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QApplication>
  16. #include <QAbstractItemView>
  17. #include <QCleanlooksStyle>
  18. #include <QDebug>
  19. #include <QDesktopWidget>
  20. #include <QLayout>
  21. #include <QMouseEvent>
  22. #include <QMenu>
  23. #include <QPainter>
  24. #include <QPointer>
  25. #include <QPushButton>
  26. #include <QStyle>
  27. #include <QStyleOptionButton>
  28. #include <QStylePainter>
  29. #include <QToolBar>
  30. // CTK includes
  31. #include "ctkCheckableComboBox.h"
  32. #include <ctkCheckableModelHelper.h>
  33. //-----------------------------------------------------------------------------
  34. class ctkCheckableComboBoxPrivate
  35. {
  36. Q_DECLARE_PUBLIC(ctkCheckableComboBox);
  37. protected:
  38. ctkCheckableComboBox* const q_ptr;
  39. QModelIndexList checkedIndexes()const;
  40. public:
  41. ctkCheckableComboBoxPrivate(ctkCheckableComboBox& object);
  42. void init();
  43. void updateCheckedList();
  44. ctkCheckableModelHelper* CheckableModelHelper;
  45. QModelIndexList CheckedList;
  46. };
  47. //-----------------------------------------------------------------------------
  48. ctkCheckableComboBoxPrivate::ctkCheckableComboBoxPrivate(ctkCheckableComboBox& object)
  49. : q_ptr(&object)
  50. {
  51. this->CheckableModelHelper = 0;
  52. }
  53. //-----------------------------------------------------------------------------
  54. void ctkCheckableComboBoxPrivate::init()
  55. {
  56. Q_Q(ctkCheckableComboBox);
  57. this->CheckableModelHelper = new ctkCheckableModelHelper(Qt::Horizontal, q);
  58. this->CheckableModelHelper->setForceCheckability(true);
  59. q->setCheckableModel(q->model());
  60. q->view()->installEventFilter(q);
  61. q->view()->viewport()->installEventFilter(q);
  62. }
  63. //-----------------------------------------------------------------------------
  64. void ctkCheckableComboBoxPrivate::updateCheckedList()
  65. {
  66. Q_Q(ctkCheckableComboBox);
  67. QModelIndexList newCheckedList = this->checkedIndexes();
  68. if (newCheckedList == this->CheckedList)
  69. {
  70. return;
  71. }
  72. this->CheckedList = newCheckedList;
  73. qDebug() << "change";
  74. emit q->checkedIndexesChanged();
  75. }
  76. //-----------------------------------------------------------------------------
  77. QModelIndexList ctkCheckableComboBoxPrivate::checkedIndexes()const
  78. {
  79. Q_Q(const ctkCheckableComboBox);
  80. return q->model()->match(
  81. q->model()->index(0,0), Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchRecursive);
  82. }
  83. //-----------------------------------------------------------------------------
  84. ctkCheckableComboBox::ctkCheckableComboBox(QWidget* parentWidget)
  85. : QComboBox(parentWidget)
  86. , d_ptr(new ctkCheckableComboBoxPrivate(*this))
  87. {
  88. Q_D(ctkCheckableComboBox);
  89. d->init();
  90. }
  91. //-----------------------------------------------------------------------------
  92. ctkCheckableComboBox::~ctkCheckableComboBox()
  93. {
  94. }
  95. //-----------------------------------------------------------------------------
  96. bool ctkCheckableComboBox::eventFilter(QObject *o, QEvent *e)
  97. {
  98. Q_D(ctkCheckableComboBox);
  99. switch (e->type())
  100. {
  101. case QEvent::MouseButtonRelease:
  102. {
  103. QMouseEvent *m = static_cast<QMouseEvent *>(e);
  104. if (this->view()->isVisible() &&
  105. this->view()->rect().contains(m->pos()) &&
  106. this->view()->currentIndex().isValid()
  107. //&& !blockMouseReleaseTimer.isActive()
  108. && (this->view()->currentIndex().flags() & Qt::ItemIsEnabled)
  109. && (this->view()->currentIndex().flags() & Qt::ItemIsSelectable))
  110. {
  111. // make the item current, it will then call QComboBox::update (and
  112. // repaint) when the current index data is changed (checkstate toggled).
  113. this->setCurrentIndex(this->view()->currentIndex().row());
  114. d->CheckableModelHelper->toggleCheckState(this->view()->currentIndex());
  115. return true;
  116. }
  117. break;
  118. }
  119. default:
  120. break;
  121. }
  122. return this->QComboBox::eventFilter(o, e);
  123. }
  124. //-----------------------------------------------------------------------------
  125. void ctkCheckableComboBox::setCheckableModel(QAbstractItemModel* newModel)
  126. {
  127. Q_D(ctkCheckableComboBox);
  128. this->disconnect(this->model(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
  129. this, SLOT(onDataChanged(const QModelIndex&, const QModelIndex&)));
  130. if (newModel != this->model())
  131. {
  132. this->setModel(newModel);
  133. }
  134. this->connect(this->model(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
  135. this, SLOT(onDataChanged(const QModelIndex&, const QModelIndex&)));
  136. d->CheckableModelHelper->setModel(newModel);
  137. d->updateCheckedList();
  138. }
  139. //-----------------------------------------------------------------------------
  140. QAbstractItemModel* ctkCheckableComboBox::checkableModel()const
  141. {
  142. return this->model();
  143. }
  144. //-----------------------------------------------------------------------------
  145. QModelIndexList ctkCheckableComboBox::checkedIndexes()const
  146. {
  147. Q_D(const ctkCheckableComboBox);
  148. return d->CheckedList;
  149. }
  150. //-----------------------------------------------------------------------------
  151. bool ctkCheckableComboBox::allChecked()const
  152. {
  153. Q_D(const ctkCheckableComboBox);
  154. return d->CheckableModelHelper->headerCheckState(0) == Qt::Checked;
  155. }
  156. //-----------------------------------------------------------------------------
  157. bool ctkCheckableComboBox::noneChecked()const
  158. {
  159. Q_D(const ctkCheckableComboBox);
  160. return d->CheckableModelHelper->headerCheckState(0) == Qt::Unchecked;
  161. }
  162. //-----------------------------------------------------------------------------
  163. void ctkCheckableComboBox::setCheckState(const QModelIndex& index, Qt::CheckState check)
  164. {
  165. Q_D(ctkCheckableComboBox);
  166. return d->CheckableModelHelper->setCheckState(index, check);
  167. }
  168. //-----------------------------------------------------------------------------
  169. Qt::CheckState ctkCheckableComboBox::checkState(const QModelIndex& index)const
  170. {
  171. Q_D(const ctkCheckableComboBox);
  172. return d->CheckableModelHelper->checkState(index);
  173. }
  174. //-----------------------------------------------------------------------------
  175. void ctkCheckableComboBox::onDataChanged(const QModelIndex& start, const QModelIndex& end)
  176. {
  177. Q_D(ctkCheckableComboBox);
  178. Q_UNUSED(start);
  179. Q_UNUSED(end);
  180. d->updateCheckedList();
  181. }
  182. //-----------------------------------------------------------------------------
  183. void ctkCheckableComboBox::paintEvent(QPaintEvent *)
  184. {
  185. QStylePainter painter(this);
  186. painter.setPen(palette().color(QPalette::Text));
  187. // draw the combobox frame, focusrect and selected etc.
  188. QStyleOptionComboBox opt;
  189. this->initStyleOption(&opt);
  190. if (this->allChecked())
  191. {
  192. opt.currentText = "All";
  193. opt.currentIcon = QIcon();
  194. }
  195. else if (this->noneChecked())
  196. {
  197. opt.currentText = "None";
  198. opt.currentIcon = QIcon();
  199. }
  200. else
  201. {
  202. //search the checked items
  203. QModelIndexList indexes = this->checkedIndexes();
  204. if (indexes.count() == 1)
  205. {
  206. opt.currentText = this->model()->data(indexes[0], Qt::DisplayRole).toString();
  207. opt.currentIcon = qvariant_cast<QIcon>(this->model()->data(indexes[0], Qt::DecorationRole));
  208. }
  209. else
  210. {
  211. QStringList indexesText;
  212. foreach(QModelIndex checkedIndex, indexes)
  213. {
  214. indexesText << this->model()->data(checkedIndex, Qt::DisplayRole).toString();
  215. }
  216. opt.currentText = indexesText.join(", ");
  217. opt.currentIcon = QIcon();
  218. }
  219. }
  220. painter.drawComplexControl(QStyle::CC_ComboBox, opt);
  221. // draw the icon and text
  222. painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
  223. }