/src/qt3support/widgets/q3widgetstack.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 571 lines · 293 code · 82 blank · 196 comment · 110 complexity · 0828ab4739dc6ae4aea15204cdaa1df1 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the Qt3Support module of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "q3widgetstack.h"
  42. #include "qlayout.h"
  43. #include "private/qlayoutengine_p.h"
  44. #include "qapplication.h"
  45. #include "qpainter.h"
  46. QT_BEGIN_NAMESPACE
  47. using namespace Qt;
  48. class Q3WidgetStackPrivate {
  49. public:
  50. class Invisible: public QWidget
  51. {
  52. public:
  53. Invisible(Q3WidgetStack * parent): QWidget(parent, "qt_invisible_widgetstack")
  54. {
  55. setBackgroundMode(NoBackground);
  56. }
  57. const char * className() const
  58. {
  59. return "Q3WidgetStackPrivate::Invisible";
  60. }
  61. protected:
  62. void paintEvent(QPaintEvent *)
  63. {
  64. QPainter(this).eraseRect(rect());
  65. }
  66. };
  67. int nextNegativeID;
  68. int nextPositiveID;
  69. };
  70. /*!
  71. \class Q3WidgetStack
  72. \brief The Q3WidgetStack class provides a stack of widgets of which
  73. only the top widget is user-visible.
  74. \compat
  75. The application programmer can move any widget to the top of the
  76. stack at any time using raiseWidget(), and add or remove widgets
  77. using addWidget() and removeWidget(). It is not sufficient to pass
  78. the widget stack as parent to a widget which should be inserted into
  79. the widgetstack.
  80. visibleWidget() is the \e get equivalent of raiseWidget(); it
  81. returns a pointer to the widget that is currently at the top of
  82. the stack.
  83. Q3WidgetStack also provides the ability to manipulate widgets
  84. through application-specified integer IDs. You can also translate
  85. from widget pointers to IDs using id() and from IDs to widget
  86. pointers using widget(). These numeric IDs are unique (per
  87. Q3WidgetStack, not globally), but Q3WidgetStack does not attach any
  88. additional meaning to them.
  89. The default widget stack is frameless, but you can use the usual
  90. Q3Frame functions (such as setFrameStyle()) to add a frame.
  91. Q3WidgetStack provides a signal, aboutToShow(), which is emitted
  92. just before a managed widget is shown.
  93. \sa Q3TabDialog QTabWidget QTabBar Q3Frame
  94. */
  95. /*!
  96. Constructs an empty widget stack.
  97. The \a parent, \a name and \a f arguments are passed to the Q3Frame
  98. constructor.
  99. */
  100. Q3WidgetStack::Q3WidgetStack(QWidget * parent, const char *name, Qt::WindowFlags f)
  101. : Q3Frame(parent, name, f) //## merge constructors in 4.0
  102. {
  103. init();
  104. }
  105. void Q3WidgetStack::init()
  106. {
  107. d = new Q3WidgetStackPrivate();
  108. d->nextNegativeID = -2;
  109. d->nextPositiveID = 0;
  110. dict = new Q3IntDict<QWidget>;
  111. focusWidgets = 0;
  112. topWidget = 0;
  113. invisible = 0;
  114. invisible = new Q3WidgetStackPrivate::Invisible(this);
  115. invisible->hide();
  116. }
  117. /*!
  118. Destroys the object and frees any allocated resources.
  119. */
  120. Q3WidgetStack::~Q3WidgetStack()
  121. {
  122. delete focusWidgets;
  123. delete d;
  124. delete dict;
  125. }
  126. /*!
  127. Adds widget \a w to this stack of widgets, with ID \a id.
  128. If you pass an id \>= 0 this ID is used. If you pass an \a id of
  129. -1 (the default), the widgets will be numbered automatically. If
  130. you pass -2 a unique negative integer will be generated. No widget
  131. has an ID of -1. Returns the ID or -1 on failure (e.g. \a w is 0).
  132. If you pass an id that is already used, then a unique negative
  133. integer will be generated to prevent two widgets having the same
  134. id.
  135. If \a w already exists in the stack the widget will be removed first.
  136. If \a w is not a child of this Q3WidgetStack moves it using
  137. reparent().
  138. */
  139. int Q3WidgetStack::addWidget(QWidget * w, int id)
  140. {
  141. if (!w || w == invisible || invisible == 0)
  142. return -1;
  143. // prevent duplicates
  144. removeWidget(w);
  145. if (id >= 0 && dict->find(id))
  146. id = -2;
  147. if (id < -1)
  148. id = d->nextNegativeID--;
  149. else if (id == -1)
  150. id = d->nextPositiveID++;
  151. else
  152. d->nextPositiveID = qMax(d->nextPositiveID, id + 1);
  153. // use id >= 0 as-is
  154. dict->insert(id, w);
  155. // preserve existing focus
  156. QWidget * f = w->focusWidget();
  157. while(f && f != w)
  158. f = f->parentWidget();
  159. if (f) {
  160. if (!focusWidgets)
  161. focusWidgets = new Q3PtrDict<QWidget>(17);
  162. focusWidgets->replace(w, w->focusWidget());
  163. }
  164. w->hide();
  165. if (w->parent() != this)
  166. w->reparent(this, contentsRect().topLeft(), false);
  167. w->setGeometry(contentsRect());
  168. updateGeometry();
  169. return id;
  170. }
  171. /*!
  172. Removes widget \a w from this stack of widgets. Does not delete \a
  173. w. If \a w is the currently visible widget, no other widget is
  174. substituted.
  175. \sa visibleWidget() raiseWidget()
  176. */
  177. void Q3WidgetStack::removeWidget(QWidget * w)
  178. {
  179. int i;
  180. if (!w || (i = id(w)) == -1)
  181. return ;
  182. dict->take(i);
  183. if (w == topWidget)
  184. topWidget = 0;
  185. if (dict->isEmpty())
  186. invisible->hide(); // let background shine through again
  187. updateGeometry();
  188. }
  189. /*!
  190. Raises the widget with ID \a id to the top of the widget stack.
  191. \sa visibleWidget()
  192. */
  193. void Q3WidgetStack::raiseWidget(int id)
  194. {
  195. if (id == -1)
  196. return;
  197. QWidget * w = dict->find(id);
  198. if (w)
  199. raiseWidget(w);
  200. }
  201. static bool isChildOf(QWidget* child, QWidget *parent)
  202. {
  203. if (!child)
  204. return false;
  205. QObjectList list = parent->children();
  206. for (int i = 0; i < list.size(); ++i) {
  207. QObject *obj = list.at(i);
  208. if (!obj->isWidgetType())
  209. continue;
  210. QWidget *widget = static_cast<QWidget *>(obj);
  211. if (!widget->isWindow())
  212. continue;
  213. if (widget == child || isChildOf(child, widget))
  214. return true;
  215. }
  216. return false;
  217. }
  218. /*!
  219. \overload
  220. Raises widget \a w to the top of the widget stack.
  221. */
  222. void Q3WidgetStack::raiseWidget(QWidget *w)
  223. {
  224. if (!w || w == invisible || w->parent() != this || w == topWidget)
  225. return;
  226. if (id(w) == -1)
  227. addWidget(w);
  228. if (!isVisible()) {
  229. topWidget = w;
  230. return;
  231. }
  232. if (w->maximumSize().width() < invisible->width()
  233. || w->maximumSize().height() < invisible->height())
  234. invisible->setBackgroundMode(backgroundMode());
  235. else if (invisible->backgroundMode() != NoBackground)
  236. invisible->setBackgroundMode(NoBackground);
  237. if (invisible->isHidden()) {
  238. invisible->setGeometry(contentsRect());
  239. invisible->lower();
  240. invisible->show();
  241. QApplication::sendPostedEvents(invisible, QEvent::ShowWindowRequest);
  242. }
  243. // try to move focus onto the incoming widget if focus
  244. // was somewhere on the outgoing widget.
  245. if (topWidget) {
  246. QWidget * fw = window()->focusWidget();
  247. if (topWidget->isAncestorOf(fw)) { // focus was on old page
  248. // look for the best focus widget we can find
  249. QWidget *p = w->focusWidget();
  250. if (!p) {
  251. // second best == first child widget in the focus chain
  252. QWidget *i = fw;
  253. while ((i = i->nextInFocusChain()) != fw) {
  254. if (((i->focusPolicy() & Qt::TabFocus) == Qt::TabFocus)
  255. && !i->focusProxy() && i->isVisibleTo(w) && i->isEnabled()
  256. && w->isAncestorOf(i)) {
  257. p = i;
  258. break;
  259. }
  260. }
  261. }
  262. if (p)
  263. p->setFocus();
  264. } else {
  265. // the focus wasn't on the old page, so we have to ensure focus doesn't go to
  266. // the widget in the page that last had focus when we show the page again.
  267. QWidget *oldfw = topWidget->focusWidget();
  268. if (oldfw)
  269. oldfw->clearFocus();
  270. }
  271. }
  272. if (isVisible()) {
  273. emit aboutToShow(w);
  274. int i = id(w);
  275. if (i != -1)
  276. emit aboutToShow(i);
  277. }
  278. topWidget = w;
  279. QObjectList c = children();
  280. for (int i = 0; i < c.size(); ++i) {
  281. QObject * o = c.at(i);
  282. if (o->isWidgetType() && o != w && o != invisible)
  283. static_cast<QWidget *>(o)->hide();
  284. }
  285. w->setGeometry(invisible->geometry());
  286. w->show();
  287. }
  288. /*!
  289. \reimp
  290. */
  291. void Q3WidgetStack::frameChanged()
  292. {
  293. Q3Frame::frameChanged();
  294. setChildGeometries();
  295. }
  296. /*!
  297. \internal
  298. */
  299. void Q3WidgetStack::setFrameRect(const QRect & r)
  300. {
  301. // ### this function used to be virtual in QFrame in Qt 3; it is no longer virtual in Qt 4
  302. Q3Frame::setFrameRect(r);
  303. setChildGeometries();
  304. }
  305. /*!
  306. Fixes up the children's geometries.
  307. */
  308. void Q3WidgetStack::setChildGeometries()
  309. {
  310. invisible->setGeometry(contentsRect());
  311. if (topWidget)
  312. topWidget->setGeometry(invisible->geometry());
  313. }
  314. /*!
  315. \reimp
  316. */
  317. void Q3WidgetStack::setVisible(bool visible)
  318. {
  319. if (visible) {
  320. // Reimplemented in order to set the children's geometries
  321. // appropriately and to pick the first widget as d->topWidget if no
  322. // topwidget was defined
  323. QObjectList c = children();
  324. if (!isVisible() && !c.isEmpty()) {
  325. for (int i = 0; i < c.size(); ++i) {
  326. QObject * o = c.at(i);
  327. if (o->isWidgetType()) {
  328. if (!topWidget && o != invisible)
  329. topWidget = static_cast<QWidget*>(o);
  330. if (o == topWidget)
  331. static_cast<QWidget *>(o)->show();
  332. else
  333. static_cast<QWidget *>(o)->hide();
  334. }
  335. }
  336. setChildGeometries();
  337. }
  338. }
  339. Q3Frame::setVisible(visible);
  340. }
  341. /*!
  342. Returns the widget with ID \a id. Returns 0 if this widget stack
  343. does not manage a widget with ID \a id.
  344. \sa id() addWidget()
  345. */
  346. QWidget * Q3WidgetStack::widget(int id) const
  347. {
  348. return id != -1 ? dict->find(id) : 0;
  349. }
  350. /*!
  351. Returns the ID of the \a widget. Returns -1 if \a widget is 0 or
  352. is not being managed by this widget stack.
  353. \sa widget() addWidget()
  354. */
  355. int Q3WidgetStack::id(QWidget * widget) const
  356. {
  357. if (!widget)
  358. return -1;
  359. Q3IntDictIterator<QWidget> it(*dict);
  360. while (it.current() && it.current() != widget)
  361. ++it;
  362. return it.current() == widget ? it.currentKey() : -1;
  363. }
  364. /*!
  365. Returns the currently visible widget (the one at the top of the
  366. stack), or 0 if nothing is currently being shown.
  367. \sa aboutToShow() id() raiseWidget()
  368. */
  369. QWidget * Q3WidgetStack::visibleWidget() const
  370. {
  371. return topWidget;
  372. }
  373. /*!
  374. \fn void Q3WidgetStack::aboutToShow(int id)
  375. This signal is emitted just before a managed widget is shown if
  376. that managed widget has an ID != -1. The \a id parameter is the numeric
  377. ID of the widget.
  378. If you call visibleWidget() in a slot connected to aboutToShow(),
  379. the widget it returns is the one that is currently visible, not
  380. the one that is about to be shown.
  381. */
  382. /*!
  383. \fn void Q3WidgetStack::aboutToShow(QWidget *widget)
  384. \overload
  385. This signal is emitted just before a managed widget is shown. The
  386. argument is a pointer to the \a widget.
  387. If you call visibleWidget() in a slot connected to aboutToShow(),
  388. the widget returned is the one that is currently visible, not the
  389. one that is about to be shown.
  390. */
  391. /*!
  392. \reimp
  393. */
  394. void Q3WidgetStack::resizeEvent(QResizeEvent * e)
  395. {
  396. Q3Frame::resizeEvent(e);
  397. setChildGeometries();
  398. }
  399. /*!
  400. \reimp
  401. */
  402. QSize Q3WidgetStack::sizeHint() const
  403. {
  404. constPolish();
  405. QSize size(0, 0);
  406. Q3IntDictIterator<QWidget> it(*dict);
  407. QWidget *w;
  408. while ((w = it.current()) != 0) {
  409. ++it;
  410. QSize sh = w->sizeHint();
  411. if (w->sizePolicy().horData() == QSizePolicy::Ignored)
  412. sh.rwidth() = 0;
  413. if (w->sizePolicy().verData() == QSizePolicy::Ignored)
  414. sh.rheight() = 0;
  415. #ifndef QT_NO_LAYOUT
  416. size = size.expandedTo(sh).expandedTo(qSmartMinSize(w));
  417. #endif
  418. }
  419. if (size.isNull())
  420. size = QSize(128, 64);
  421. size += QSize(2*frameWidth(), 2*frameWidth());
  422. return size;
  423. }
  424. /*!
  425. \reimp
  426. */
  427. QSize Q3WidgetStack::minimumSizeHint() const
  428. {
  429. constPolish();
  430. QSize size(0, 0);
  431. Q3IntDictIterator<QWidget> it(*dict);
  432. QWidget *w;
  433. while ((w = it.current()) != 0) {
  434. ++it;
  435. QSize sh = w->minimumSizeHint();
  436. if (w->sizePolicy().horData() == QSizePolicy::Ignored)
  437. sh.rwidth() = 0;
  438. if (w->sizePolicy().verData() == QSizePolicy::Ignored)
  439. sh.rheight() = 0;
  440. #ifndef QT_NO_LAYOUT
  441. size = size.expandedTo(sh).expandedTo(w->minimumSize());
  442. #endif
  443. }
  444. if (size.isNull())
  445. size = QSize(64, 32);
  446. size += QSize(2*frameWidth(), 2*frameWidth());
  447. return size;
  448. }
  449. /*!
  450. \reimp
  451. */
  452. void Q3WidgetStack::childEvent(QChildEvent *e)
  453. {
  454. if (e->child()->isWidgetType() && e->removed())
  455. removeWidget((QWidget *) e->child());
  456. }
  457. /*!
  458. \reimp
  459. */
  460. bool Q3WidgetStack::event(QEvent* e)
  461. {
  462. if (e->type() == QEvent::LayoutRequest || e->type() == QEvent::LayoutHint )
  463. updateGeometry(); // propgate layout hints to parent
  464. return Q3Frame::event(e);
  465. }
  466. QT_END_NAMESPACE