ctkMessageBox.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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.apache.org/licenses/LICENSE-2.0.txt
  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 <QCheckBox>
  16. #include <QDebug>
  17. #include <QGridLayout>
  18. #include <QPushButton>
  19. #include <QSettings>
  20. #include <QTimer>
  21. // CTK includes
  22. #include "ctkMessageBox.h"
  23. //-----------------------------------------------------------------------------
  24. // ctkMessageBoxPrivate methods
  25. //-----------------------------------------------------------------------------
  26. class ctkMessageBoxPrivate
  27. {
  28. Q_DECLARE_PUBLIC(ctkMessageBox);
  29. protected:
  30. ctkMessageBox* const q_ptr;
  31. public:
  32. explicit ctkMessageBoxPrivate(ctkMessageBox& object);
  33. virtual ~ctkMessageBoxPrivate();
  34. void init();
  35. int dontShowAgainButtonOrRole();
  36. QAbstractButton* button(int buttonOrRole);
  37. int buttonFromSettings();
  38. void readSettings();
  39. void writeSettings(int button);
  40. public:
  41. QString DontShowAgainSettingsKey;
  42. QCheckBox* DontShowAgainCheckBox;
  43. bool SaveDontShowAgainSettingsOnAcceptOnly;
  44. };
  45. //-----------------------------------------------------------------------------
  46. ctkMessageBoxPrivate::ctkMessageBoxPrivate(ctkMessageBox& object)
  47. : q_ptr(&object)
  48. {
  49. this->DontShowAgainSettingsKey = QString();
  50. this->DontShowAgainCheckBox = 0;
  51. this->SaveDontShowAgainSettingsOnAcceptOnly = true;
  52. }
  53. //-----------------------------------------------------------------------------
  54. ctkMessageBoxPrivate::~ctkMessageBoxPrivate()
  55. {
  56. }
  57. //-----------------------------------------------------------------------------
  58. void ctkMessageBoxPrivate::init()
  59. {
  60. Q_Q(ctkMessageBox);
  61. this->DontShowAgainCheckBox = new QCheckBox(q);
  62. this->DontShowAgainCheckBox->setObjectName(QLatin1String("ctk_msgbox_dontshowcheckbox"));
  63. this->DontShowAgainCheckBox->setText(q->tr("Don't show this message again"));
  64. // The height policy being Fixed by default on a checkbox, if the message box icon
  65. // is bigger than the text+checkbox height, it would be truncated.
  66. this->DontShowAgainCheckBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  67. this->DontShowAgainCheckBox->setChecked(false);
  68. this->DontShowAgainCheckBox->hide();
  69. }
  70. //-----------------------------------------------------------------------------
  71. int ctkMessageBoxPrivate::dontShowAgainButtonOrRole()
  72. {
  73. int buttonOrRole = QMessageBox::InvalidRole;
  74. if (this->DontShowAgainCheckBox->isChecked())
  75. {
  76. buttonOrRole = this->buttonFromSettings();
  77. if (buttonOrRole == QMessageBox::InvalidRole)
  78. {
  79. buttonOrRole = QMessageBox::AcceptRole;
  80. }
  81. }
  82. return buttonOrRole;
  83. }
  84. //-----------------------------------------------------------------------------
  85. QAbstractButton* ctkMessageBoxPrivate::button(int buttonOrRole)
  86. {
  87. Q_Q(ctkMessageBox);
  88. QAbstractButton* autoAcceptButton = 0;
  89. // Special case when no button is in a dialog, QMessageBox adds the Ok
  90. // button automatically.
  91. if (q->buttons().size() == 0 &&
  92. buttonOrRole != QMessageBox::InvalidRole)
  93. {
  94. q->addButton(QMessageBox::Ok);
  95. }
  96. if ( q->standardButtons() & buttonOrRole)
  97. {
  98. autoAcceptButton = q->button(static_cast<QMessageBox::StandardButton>(buttonOrRole));
  99. }
  100. else
  101. {
  102. foreach(QAbstractButton* button, q->buttons())
  103. {
  104. if (q->buttonRole(button) == buttonOrRole)
  105. {
  106. autoAcceptButton = button;
  107. break;
  108. }
  109. }
  110. }
  111. return autoAcceptButton;
  112. }
  113. //-----------------------------------------------------------------------------
  114. int ctkMessageBoxPrivate::buttonFromSettings()
  115. {
  116. QSettings settings;
  117. int button = settings.value(this->DontShowAgainSettingsKey,
  118. static_cast<int>(QMessageBox::InvalidRole)).toInt();
  119. return button;
  120. }
  121. //-----------------------------------------------------------------------------
  122. void ctkMessageBoxPrivate::readSettings()
  123. {
  124. if (this->DontShowAgainSettingsKey.isEmpty())
  125. {
  126. return;
  127. }
  128. int button = this->buttonFromSettings();
  129. this->DontShowAgainCheckBox->setChecked(button != QMessageBox::InvalidRole);
  130. }
  131. //-----------------------------------------------------------------------------
  132. void ctkMessageBoxPrivate::writeSettings(int button)
  133. {
  134. if (this->DontShowAgainSettingsKey.isEmpty())
  135. {
  136. return;
  137. }
  138. QSettings settings;
  139. settings.setValue(this->DontShowAgainSettingsKey,
  140. QVariant(this->DontShowAgainCheckBox->isChecked() ?
  141. button : QMessageBox::InvalidRole));
  142. }
  143. //-----------------------------------------------------------------------------
  144. // ctkMessageBox methods
  145. //-----------------------------------------------------------------------------
  146. ctkMessageBox::ctkMessageBox(QWidget* newParent)
  147. : Superclass(newParent)
  148. , d_ptr(new ctkMessageBoxPrivate(*this))
  149. {
  150. Q_D(ctkMessageBox);
  151. d->init();
  152. }
  153. //-----------------------------------------------------------------------------
  154. ctkMessageBox::ctkMessageBox(Icon icon, const QString& title,
  155. const QString& text, StandardButtons buttons,
  156. QWidget* parent, Qt::WindowFlags f)
  157. : QMessageBox(icon, title, text, buttons, parent, f)
  158. {
  159. Q_D(ctkMessageBox);
  160. d->init();
  161. }
  162. //-----------------------------------------------------------------------------
  163. ctkMessageBox::~ctkMessageBox()
  164. {
  165. }
  166. //-----------------------------------------------------------------------------
  167. void ctkMessageBox::setDontShowAgainVisible(bool visible)
  168. {
  169. Q_D(ctkMessageBox);
  170. if (!visible)
  171. {
  172. #if (QT_VERSION < QT_VERSION_CHECK(5, 2, 0))
  173. this->layout()->removeWidget(d->DontShowAgainCheckBox);
  174. #endif
  175. d->DontShowAgainCheckBox->hide();
  176. return;
  177. }
  178. d->DontShowAgainCheckBox->setVisible(true);
  179. // update the text from the button with the accept role
  180. QAbstractButton *acceptButton = d->button(QMessageBox::AcceptRole);
  181. if (acceptButton && !acceptButton->text().isEmpty())
  182. {
  183. QString dontShowAgainText =
  184. this->tr("Don't show this message again and always %1").arg(acceptButton->text());
  185. d->DontShowAgainCheckBox->setText(dontShowAgainText);
  186. }
  187. #if (QT_VERSION < QT_VERSION_CHECK(5, 2, 0))
  188. QGridLayout *grid = static_cast<QGridLayout *>(this->layout());
  189. grid->addWidget(d->DontShowAgainCheckBox, 1, 1, 1, 1);
  190. #else
  191. this->setCheckBox(d->DontShowAgainCheckBox);
  192. #endif
  193. }
  194. //-----------------------------------------------------------------------------
  195. bool ctkMessageBox::isDontShowAgainVisible()const
  196. {
  197. Q_D(const ctkMessageBox);
  198. return d->DontShowAgainCheckBox->isVisibleTo(const_cast<ctkMessageBox*>(this));
  199. }
  200. //-----------------------------------------------------------------------------
  201. void ctkMessageBox::setDontShowAgainSettingsKey(const QString& key)
  202. {
  203. Q_D(ctkMessageBox);
  204. if (key == d->DontShowAgainSettingsKey)
  205. {
  206. return;
  207. }
  208. d->DontShowAgainSettingsKey = key;
  209. d->readSettings();
  210. this->setDontShowAgainVisible(!key.isEmpty());
  211. }
  212. //-----------------------------------------------------------------------------
  213. QString ctkMessageBox::dontShowAgainSettingsKey()const
  214. {
  215. Q_D(const ctkMessageBox);
  216. return d->DontShowAgainSettingsKey;
  217. }
  218. //-----------------------------------------------------------------------------
  219. bool ctkMessageBox::dontShowAgain()const
  220. {
  221. Q_D(const ctkMessageBox);
  222. return d->DontShowAgainCheckBox->isChecked();
  223. }
  224. //-----------------------------------------------------------------------------
  225. void ctkMessageBox::setDontShowAgain(bool dontShow)
  226. {
  227. Q_D(ctkMessageBox);
  228. d->DontShowAgainCheckBox->setChecked(dontShow);
  229. // We don't write into settings here because we want the same behavior
  230. // as if the user clicked on the checkbox.
  231. // If you want to save the preference into settings even if the user
  232. // escape/cancel/reject the dialog, then you must set the QSettings value
  233. // manually
  234. }
  235. //-----------------------------------------------------------------------------
  236. void ctkMessageBox::done(int resultCode)
  237. {
  238. Q_D(ctkMessageBox);
  239. // Don't save if the button is not an accepting button
  240. if (!d->SaveDontShowAgainSettingsOnAcceptOnly ||
  241. this->buttonRole( this->clickedButton() ) == QMessageBox::AcceptRole )
  242. {
  243. d->writeSettings(resultCode);
  244. }
  245. this->Superclass::done(resultCode);
  246. }
  247. //-----------------------------------------------------------------------------
  248. void ctkMessageBox::setVisible(bool visible)
  249. {
  250. Q_D(ctkMessageBox);
  251. if (visible)
  252. {
  253. int dontShowAgainButtonOrRole = d->dontShowAgainButtonOrRole();
  254. QAbstractButton* autoAcceptButton = d->button(dontShowAgainButtonOrRole);
  255. if (autoAcceptButton)
  256. {
  257. // Don't call click now, it would destroy the message box. The calling
  258. // function might expect the message box to be still valid after
  259. // setVisible() return.
  260. QTimer::singleShot(0, autoAcceptButton, SLOT(click()));
  261. return;
  262. }
  263. }
  264. this->Superclass::setVisible(visible);
  265. }
  266. //-----------------------------------------------------------------------------
  267. bool ctkMessageBox
  268. ::confirmExit(const QString& dontShowAgainKey, QWidget* parentWidget)
  269. {
  270. ctkMessageBox* dialog = new ctkMessageBox(parentWidget);
  271. // this will take care of destroying the window
  272. // regardless the parent widget is null or non-null.
  273. dialog->setAttribute(Qt::WA_DeleteOnClose);
  274. dialog->setText(tr("Are you sure you want to exit?"));
  275. dialog->setIcon(QMessageBox::Question);
  276. dialog->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
  277. dialog->setDontShowAgainSettingsKey(dontShowAgainKey);
  278. return dialog->exec() == QMessageBox::Ok;
  279. }