/src/qt3support/widgets/q3dockwindow.cpp

https://bitbucket.org/ultra_iter/qt-vtl
C++ | 2115 lines | 1417 code | 201 blank | 497 comment | 397 complexity | d4a610789bc0de297e683c5483b14870 MD5 | raw file

Large files are truncated, but you can click here to view the full 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 "q3dockwindow.h"
  42. #ifndef QT_NO_MAINWINDOW
  43. #include "qapplication.h"
  44. #include "qcursor.h"
  45. #include "qdesktopwidget.h"
  46. #include "q3dockarea.h"
  47. #include "qevent.h"
  48. #include "qlayout.h"
  49. #include "q3mainwindow.h"
  50. #include "qpainter.h"
  51. #include "qpointer.h"
  52. #include "qstyle.h"
  53. #include "qstyleoption.h"
  54. #include "qtimer.h"
  55. #include "q3toolbar.h"
  56. #include "qtoolbutton.h"
  57. #include "qtooltip.h"
  58. #include <private/q3titlebar_p.h>
  59. #include <private/qwidgetresizehandler_p.h>
  60. #include <qrubberband.h>
  61. #include <qdebug.h>
  62. QT_BEGIN_NAMESPACE
  63. #ifdef Q_WS_MAC
  64. static bool default_opaque = true;
  65. #else
  66. static bool default_opaque = false;
  67. #endif
  68. class Q3DockWindowPrivate
  69. {
  70. };
  71. class Q3DockWindowResizeHandle : public QWidget
  72. {
  73. Q_OBJECT
  74. public:
  75. Q3DockWindowResizeHandle(Qt::Orientation o, QWidget *parent, Q3DockWindow *w, const char* /*name*/=0);
  76. void setOrientation(Qt::Orientation o);
  77. Qt::Orientation orientation() const { return orient; }
  78. QSize sizeHint() const;
  79. protected:
  80. void paintEvent(QPaintEvent *);
  81. void mouseMoveEvent(QMouseEvent *);
  82. void mousePressEvent(QMouseEvent *);
  83. void mouseReleaseEvent(QMouseEvent *);
  84. bool event(QEvent *event);
  85. private:
  86. void startLineDraw();
  87. void endLineDraw();
  88. void drawLine(const QPoint &globalPos);
  89. private:
  90. Qt::Orientation orient;
  91. bool mousePressed;
  92. QRubberBand *rubberBand;
  93. QPoint lastPos, firstPos;
  94. Q3DockWindow *dockWindow;
  95. bool mouseOver;
  96. };
  97. Q3DockWindowResizeHandle::Q3DockWindowResizeHandle(Qt::Orientation o, QWidget *parent,
  98. Q3DockWindow *w, const char *)
  99. : QWidget(parent, "qt_dockwidget_internal"), mousePressed(false), rubberBand(0), dockWindow(w),
  100. mouseOver(false)
  101. {
  102. setOrientation(o);
  103. }
  104. QSize Q3DockWindowResizeHandle::sizeHint() const
  105. {
  106. QStyleOptionQ3DockWindow opt;
  107. opt.init(this);
  108. if (!dockWindow->area() || dockWindow->area()->orientation() == Qt::Horizontal)
  109. opt.state |= QStyle::State_Horizontal;
  110. opt.rect = rect();
  111. opt.docked = dockWindow->area();
  112. opt.closeEnabled = dockWindow->isCloseEnabled();
  113. int sw = 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, &opt, this) / 3;
  114. return (style()->sizeFromContents(QStyle::CT_Q3DockWindow, &opt, QSize(sw, sw), this).expandedTo(QApplication::globalStrut()));
  115. }
  116. void Q3DockWindowResizeHandle::setOrientation(Qt::Orientation o)
  117. {
  118. orient = o;
  119. if (o == Qt::Horizontal) {
  120. #ifndef QT_NO_CURSOR
  121. setCursor(Qt::splitVCursor);
  122. #endif
  123. setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
  124. } else {
  125. #ifndef QT_NO_CURSOR
  126. setCursor(Qt::splitHCursor);
  127. #endif
  128. setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
  129. }
  130. }
  131. void Q3DockWindowResizeHandle::mousePressEvent(QMouseEvent *e)
  132. {
  133. e->ignore();
  134. if (e->button() != Qt::LeftButton)
  135. return;
  136. e->accept();
  137. mousePressed = true;
  138. if (!dockWindow->opaqueMoving())
  139. startLineDraw();
  140. lastPos = firstPos = e->globalPos();
  141. if (!dockWindow->opaqueMoving())
  142. drawLine(e->globalPos());
  143. }
  144. void Q3DockWindowResizeHandle::mouseMoveEvent(QMouseEvent *e)
  145. {
  146. if (!mousePressed)
  147. return;
  148. if (!dockWindow->opaqueMoving()) {
  149. if (orientation() != dockWindow->area()->orientation()) {
  150. if (orientation() == Qt::Horizontal) {
  151. int minpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).y();
  152. int maxpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).y() + dockWindow->area()->height();
  153. if (e->globalPos().y() < minpos || e->globalPos().y() > maxpos)
  154. return;
  155. } else {
  156. int minpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).x();
  157. int maxpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).x() + dockWindow->area()->width();
  158. if (e->globalPos().x() < minpos || e->globalPos().x() > maxpos)
  159. return;
  160. }
  161. } else {
  162. QWidget *w = dockWindow->area()->window();
  163. if (w) {
  164. if (orientation() == Qt::Horizontal) {
  165. int minpos = w->mapToGlobal(QPoint(0, 0)).y();
  166. int maxpos = w->mapToGlobal(QPoint(0, 0)).y() + w->height();
  167. if (e->globalPos().y() < minpos || e->globalPos().y() > maxpos)
  168. return;
  169. } else {
  170. int minpos = w->mapToGlobal(QPoint(0, 0)).x();
  171. int maxpos = w->mapToGlobal(QPoint(0, 0)).x() + w->width();
  172. if (e->globalPos().x() < minpos || e->globalPos().x() > maxpos)
  173. return;
  174. }
  175. }
  176. }
  177. }
  178. if (!dockWindow->opaqueMoving())
  179. drawLine(lastPos);
  180. lastPos = e->globalPos();
  181. if (dockWindow->opaqueMoving()) {
  182. mouseReleaseEvent(e);
  183. mousePressed = true;
  184. firstPos = e->globalPos();
  185. }
  186. if (!dockWindow->opaqueMoving())
  187. drawLine(e->globalPos());
  188. }
  189. void Q3DockWindowResizeHandle::mouseReleaseEvent(QMouseEvent *e)
  190. {
  191. if (mousePressed) {
  192. if (!dockWindow->opaqueMoving()) {
  193. drawLine(lastPos);
  194. endLineDraw();
  195. }
  196. if (orientation() != dockWindow->area()->orientation())
  197. dockWindow->area()->invalidNextOffset(dockWindow);
  198. if (orientation() == Qt::Horizontal) {
  199. int dy;
  200. if (dockWindow->area()->handlePosition() == Q3DockArea::Normal || orientation() != dockWindow->area()->orientation())
  201. dy = e->globalPos().y() - firstPos.y();
  202. else
  203. dy = firstPos.y() - e->globalPos().y();
  204. int d = dockWindow->height() + dy;
  205. if (orientation() != dockWindow->area()->orientation()) {
  206. dockWindow->setFixedExtentHeight(-1);
  207. d = qMax(d, dockWindow->minimumHeight());
  208. int ms = dockWindow->area()->maxSpace(d, dockWindow);
  209. d = qMin(d, ms);
  210. dockWindow->setFixedExtentHeight(d);
  211. } else {
  212. dockWindow->area()->setFixedExtent(d, dockWindow);
  213. }
  214. } else {
  215. int dx;
  216. if (dockWindow->area()->handlePosition() == Q3DockArea::Normal || orientation() != dockWindow->area()->orientation())
  217. dx = e->globalPos().x() - firstPos.x();
  218. else
  219. dx = firstPos.x() - e->globalPos().x();
  220. int d = dockWindow->width() + dx;
  221. if (orientation() != dockWindow->area()->orientation()) {
  222. dockWindow->setFixedExtentWidth(-1);
  223. d = qMax(d, dockWindow->minimumWidth());
  224. int ms = dockWindow->area()->maxSpace(d, dockWindow);
  225. d = qMin(d, ms);
  226. dockWindow->setFixedExtentWidth(d);
  227. } else {
  228. dockWindow->area()->setFixedExtent(d, dockWindow);
  229. }
  230. }
  231. }
  232. QApplication::postEvent(dockWindow->area(), new QEvent(QEvent::LayoutHint));
  233. mousePressed = false;
  234. }
  235. bool Q3DockWindowResizeHandle::event(QEvent *event)
  236. {
  237. switch (event->type()) {
  238. case QEvent::HoverEnter:
  239. if (!mouseOver) {
  240. mouseOver = true;
  241. update();
  242. }
  243. break;
  244. case QEvent::HoverLeave:
  245. if (mouseOver) {
  246. mouseOver = false;
  247. update();
  248. }
  249. break;
  250. default:
  251. break;
  252. }
  253. return QWidget::event(event);
  254. }
  255. void Q3DockWindowResizeHandle::paintEvent(QPaintEvent *)
  256. {
  257. QPainter p(this);
  258. QStyleOption opt(0);
  259. opt.init(this);
  260. if (orientation() == Qt::Horizontal)
  261. opt.state |= QStyle::State_Horizontal;
  262. style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, &p, this);
  263. }
  264. void Q3DockWindowResizeHandle::startLineDraw()
  265. {
  266. if (rubberBand)
  267. endLineDraw();
  268. rubberBand = new QRubberBand(QRubberBand::Line);
  269. rubberBand->setGeometry(-1, -1, 1, 1);
  270. rubberBand->show();
  271. }
  272. void Q3DockWindowResizeHandle::endLineDraw()
  273. {
  274. delete rubberBand;
  275. rubberBand = 0;
  276. }
  277. void Q3DockWindowResizeHandle::drawLine(const QPoint &globalPos)
  278. {
  279. QPoint start = mapToGlobal(QPoint(0, 0));
  280. QPoint starta = dockWindow->area()->mapToGlobal(QPoint(0, 0));
  281. QPoint end = globalPos;
  282. if (orientation() == Qt::Horizontal) {
  283. if (orientation() == dockWindow->orientation())
  284. rubberBand->setGeometry(starta.x(), end.y(), dockWindow->area()->width(), height());
  285. else
  286. rubberBand->setGeometry(start.x(), end.y(), width(), height());
  287. } else {
  288. if (orientation() == dockWindow->orientation())
  289. rubberBand->setGeometry(end.x(), starta.y(), width(), dockWindow->area()->height());
  290. else
  291. rubberBand->setGeometry(end.x(), start.y(), width(), height());
  292. }
  293. }
  294. static QPoint realWidgetPos(Q3DockWindow *w)
  295. {
  296. if (!w->parentWidget() || w->place() == Q3DockWindow::OutsideDock)
  297. return w->pos();
  298. return w->parentWidget()->mapToGlobal(w->geometry().topLeft());
  299. }
  300. class Q3DockWindowHandle : public QWidget
  301. {
  302. Q_OBJECT
  303. Q_PROPERTY(QString windowTitle READ windowTitle)
  304. friend class Q3DockWindow;
  305. friend class Q3DockWindowTitleBar;
  306. public:
  307. Q3DockWindowHandle(Q3DockWindow *dw);
  308. void updateGui();
  309. QSize minimumSizeHint() const;
  310. QSize minimumSize() const { return minimumSizeHint(); }
  311. QSize sizeHint() const { return minimumSize(); }
  312. void setOpaqueMoving(bool b) { opaque = b; }
  313. QString windowTitle() const { return dockWindow->windowTitle(); }
  314. signals:
  315. void doubleClicked();
  316. protected:
  317. void paintEvent(QPaintEvent *e);
  318. void resizeEvent(QResizeEvent *e);
  319. void mousePressEvent(QMouseEvent *e);
  320. void mouseMoveEvent(QMouseEvent *e);
  321. void mouseReleaseEvent(QMouseEvent *e);
  322. void mouseDoubleClickEvent(QMouseEvent *e);
  323. void keyPressEvent(QKeyEvent *e);
  324. void keyReleaseEvent(QKeyEvent *e);
  325. void changeEvent(QEvent *);
  326. private slots:
  327. void minimize();
  328. private:
  329. Q3DockWindow *dockWindow;
  330. QPoint offset;
  331. QToolButton *closeButton;
  332. QTimer *timer;
  333. uint opaque : 1;
  334. uint mousePressed : 1;
  335. uint hadDblClick : 1;
  336. uint ctrlDown : 1;
  337. QPointer<QWidget> oldFocus;
  338. };
  339. class Q3DockWindowTitleBar : public Q3TitleBar
  340. {
  341. Q_OBJECT
  342. friend class Q3DockWindow;
  343. friend class Q3DockWindowHandle;
  344. public:
  345. Q3DockWindowTitleBar(Q3DockWindow *dw);
  346. void updateGui();
  347. void setOpaqueMoving(bool b) { opaque = b; }
  348. protected:
  349. void resizeEvent(QResizeEvent *e);
  350. void mousePressEvent(QMouseEvent *e);
  351. void mouseMoveEvent(QMouseEvent *e);
  352. void mouseReleaseEvent(QMouseEvent *e);
  353. void mouseDoubleClickEvent(QMouseEvent *e);
  354. void keyPressEvent(QKeyEvent *e);
  355. void keyReleaseEvent(QKeyEvent *e);
  356. private:
  357. Q3DockWindow *dockWindow;
  358. QPoint offset;
  359. uint mousePressed : 1;
  360. uint hadDblClick : 1;
  361. uint opaque : 1;
  362. uint ctrlDown : 1;
  363. QPointer<QWidget> oldFocus;
  364. };
  365. Q3DockWindowHandle::Q3DockWindowHandle(Q3DockWindow *dw)
  366. : QWidget(dw, "qt_dockwidget_internal"), dockWindow(dw),
  367. closeButton(0), opaque(default_opaque), mousePressed(false)
  368. {
  369. ctrlDown = false;
  370. timer = new QTimer(this);
  371. connect(timer, SIGNAL(timeout()), this, SLOT(minimize()));
  372. #if defined(Q_WS_WIN) && !defined(QT_NO_CURSOR)
  373. setCursor(Qt::SizeAllCursor);
  374. #endif
  375. }
  376. void Q3DockWindowHandle::paintEvent(QPaintEvent *e)
  377. {
  378. if (!dockWindow->dockArea && !opaque)
  379. return;
  380. QPainter p(this);
  381. QStyleOptionQ3DockWindow opt;
  382. opt.init(this);
  383. if (!dockWindow->area() || dockWindow->area()->orientation() == Qt::Horizontal)
  384. opt.state |= QStyle::State_Horizontal;
  385. opt.rect = rect();
  386. opt.docked = dockWindow->area();
  387. opt.closeEnabled = dockWindow->isCloseEnabled();
  388. opt.rect = QStyle::visualRect(opt.direction, opt.rect,
  389. style()->subElementRect(QStyle::SE_Q3DockWindowHandleRect, &opt, this));
  390. style()->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
  391. QWidget::paintEvent(e);
  392. }
  393. void Q3DockWindowHandle::keyPressEvent(QKeyEvent *e)
  394. {
  395. if (!mousePressed)
  396. return;
  397. if (e->key() == Qt::Key_Control) {
  398. ctrlDown = true;
  399. dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
  400. }
  401. }
  402. void Q3DockWindowHandle::keyReleaseEvent(QKeyEvent *e)
  403. {
  404. if (!mousePressed)
  405. return;
  406. if (e->key() == Qt::Key_Control) {
  407. ctrlDown = false;
  408. dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
  409. }
  410. }
  411. void Q3DockWindowHandle::mousePressEvent(QMouseEvent *e)
  412. {
  413. if (!dockWindow->dockArea)
  414. return;
  415. ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
  416. oldFocus = qApp->focusWidget();
  417. setFocus();
  418. e->ignore();
  419. if (e->button() != Qt::LeftButton)
  420. return;
  421. e->accept();
  422. hadDblClick = false;
  423. mousePressed = true;
  424. offset = e->pos();
  425. dockWindow->startRectDraw(mapToGlobal(e->pos()), !opaque);
  426. if (!opaque)
  427. qApp->installEventFilter(dockWindow);
  428. }
  429. void Q3DockWindowHandle::mouseMoveEvent(QMouseEvent *e)
  430. {
  431. if (!mousePressed || e->pos() == offset)
  432. return;
  433. ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
  434. dockWindow->handleMove(e->pos() - offset, e->globalPos(), !opaque);
  435. if (opaque)
  436. dockWindow->updatePosition(e->globalPos());
  437. }
  438. void Q3DockWindowHandle::mouseReleaseEvent(QMouseEvent *e)
  439. {
  440. ctrlDown = false;
  441. qApp->removeEventFilter(dockWindow);
  442. if (oldFocus)
  443. oldFocus->setFocus();
  444. if (!mousePressed)
  445. return;
  446. dockWindow->endRectDraw(!opaque);
  447. mousePressed = false;
  448. #ifdef Q_WS_MAC
  449. releaseMouse();
  450. #endif
  451. if (!hadDblClick && offset == e->pos()) {
  452. timer->start(QApplication::doubleClickInterval(), true);
  453. } else if (!hadDblClick) {
  454. dockWindow->updatePosition(e->globalPos());
  455. }
  456. if (opaque)
  457. dockWindow->titleBar->mousePressed = false;
  458. if (dockWindow->parentWidget())
  459. QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
  460. }
  461. void Q3DockWindowHandle::minimize()
  462. {
  463. if (!dockWindow->area())
  464. return;
  465. Q3MainWindow *mw = qobject_cast<Q3MainWindow*>(dockWindow->area()->parentWidget());
  466. if (mw && mw->isDockEnabled(dockWindow, Qt::DockMinimized))
  467. mw->moveDockWindow(dockWindow, Qt::DockMinimized);
  468. }
  469. void Q3DockWindowHandle::resizeEvent(QResizeEvent *)
  470. {
  471. updateGui();
  472. }
  473. void Q3DockWindowHandle::updateGui()
  474. {
  475. updateGeometry();
  476. if (!closeButton) {
  477. closeButton = new QToolButton(this, "qt_close_button1");
  478. #ifndef QT_NO_CURSOR
  479. closeButton->setCursor(Qt::ArrowCursor);
  480. #endif
  481. QStyleOption opt(0);
  482. opt.init(closeButton);
  483. closeButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton, &opt,
  484. closeButton));
  485. closeButton->setFixedSize(12, 12);
  486. connect(closeButton, SIGNAL(clicked()),
  487. dockWindow, SLOT(hide()));
  488. }
  489. if (dockWindow->isCloseEnabled() && dockWindow->area())
  490. closeButton->show();
  491. else
  492. closeButton->hide();
  493. if (!dockWindow->area())
  494. return;
  495. if (dockWindow->area()->orientation() == Qt::Horizontal) {
  496. int off = (width() - closeButton->width() - 1) / 2;
  497. closeButton->move(off, 2);
  498. } else {
  499. int off = (height() - closeButton->height() - 1) / 2;
  500. int x = QApplication::reverseLayout() ? 2 : width() - closeButton->width() - 2;
  501. closeButton->move(x, off);
  502. }
  503. }
  504. void Q3DockWindowHandle::changeEvent(QEvent *ev)
  505. {
  506. if(ev->type() == QEvent::StyleChange) {
  507. if (closeButton) {
  508. QStyleOption opt(0);
  509. opt.init(closeButton);
  510. closeButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton,
  511. &opt, closeButton));
  512. }
  513. }
  514. QWidget::changeEvent(ev);
  515. }
  516. QSize Q3DockWindowHandle::minimumSizeHint() const
  517. {
  518. if (!dockWindow->dockArea)
  519. return QSize(0, 0);
  520. int wh = dockWindow->isCloseEnabled() ? 17 : style()->pixelMetric(QStyle::PM_ToolBarHandleExtent, 0, this);
  521. if (dockWindow->orientation() == Qt::Horizontal)
  522. return QSize(wh, 0);
  523. return QSize(0, wh);
  524. }
  525. void Q3DockWindowHandle::mouseDoubleClickEvent(QMouseEvent *e)
  526. {
  527. e->ignore();
  528. if (e->button() != Qt::LeftButton)
  529. return;
  530. e->accept();
  531. timer->stop();
  532. emit doubleClicked();
  533. hadDblClick = true;
  534. if (dockWindow->parentWidget())
  535. QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
  536. }
  537. Q3DockWindowTitleBar::Q3DockWindowTitleBar(Q3DockWindow *dw)
  538. : Q3TitleBar(0, dw), dockWindow(dw),
  539. mousePressed(false), hadDblClick(false), opaque(default_opaque)
  540. {
  541. setObjectName(QLatin1String("qt_dockwidget_internal"));
  542. ctrlDown = false;
  543. setMouseTracking(true);
  544. QStyleOptionTitleBar opt = getStyleOption();
  545. setFixedHeight(style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
  546. connect(this, SIGNAL(doClose()), dockWindow, SLOT(hide()));
  547. }
  548. void Q3DockWindowTitleBar::keyPressEvent(QKeyEvent *e)
  549. {
  550. if (!mousePressed)
  551. return;
  552. if (e->key() == Qt::Key_Control) {
  553. ctrlDown = true;
  554. dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
  555. }
  556. }
  557. void Q3DockWindowTitleBar::keyReleaseEvent(QKeyEvent *e)
  558. {
  559. if (!mousePressed)
  560. return;
  561. if (e->key() == Qt::Key_Control) {
  562. ctrlDown = false;
  563. dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
  564. }
  565. }
  566. void Q3DockWindowTitleBar::mousePressEvent(QMouseEvent *e)
  567. {
  568. QStyleOptionTitleBar opt;
  569. opt.init(this);
  570. opt.subControls = QStyle::SC_All;
  571. opt.activeSubControls = QStyle::SC_None;
  572. opt.text = windowTitle();
  573. //################
  574. QIcon icon = windowIcon();
  575. QSize s = icon.actualSize(QSize(64, 64));
  576. opt.icon = icon.pixmap(s);
  577. opt.titleBarState = window() ? window()->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
  578. opt.titleBarFlags = fakeWindowFlags();
  579. QStyle::SubControl tbctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
  580. e->pos(), this);
  581. if (tbctrl < QStyle::SC_TitleBarLabel && tbctrl != QStyle::SC_None) {
  582. Q3TitleBar::mousePressEvent(e);
  583. return;
  584. }
  585. ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
  586. oldFocus = qApp->focusWidget();
  587. // setFocus activates the window, which deactivates the main window
  588. // not what we want, and not required anyway on Windows
  589. #ifndef Q_WS_WIN
  590. setFocus();
  591. #endif
  592. e->ignore();
  593. if (e->button() != Qt::LeftButton)
  594. return;
  595. if (e->y() < 3 && dockWindow->isResizeEnabled())
  596. return;
  597. e->accept();
  598. bool oldPressed = mousePressed;
  599. mousePressed = true;
  600. hadDblClick = false;
  601. offset = e->pos();
  602. dockWindow->startRectDraw(mapToGlobal(e->pos()), !opaque);
  603. // grabMouse resets the Windows mouse press count, so we never receive a double click on Windows
  604. // not required on Windows, and did work on X11, too, but no problem there in the first place
  605. #ifndef Q_WS_WIN
  606. if(!oldPressed && dockWindow->opaqueMoving())
  607. grabMouse();
  608. #else
  609. Q_UNUSED(oldPressed);
  610. #endif
  611. }
  612. void Q3DockWindowTitleBar::mouseMoveEvent(QMouseEvent *e)
  613. {
  614. if (!mousePressed) {
  615. Q3TitleBar::mouseMoveEvent(e);
  616. return;
  617. }
  618. ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
  619. e->accept();
  620. dockWindow->handleMove(e->pos() - offset, e->globalPos(), !opaque);
  621. }
  622. void Q3DockWindowTitleBar::mouseReleaseEvent(QMouseEvent *e)
  623. {
  624. if (!mousePressed) {
  625. Q3TitleBar::mouseReleaseEvent(e);
  626. return;
  627. }
  628. ctrlDown = false;
  629. qApp->removeEventFilter(dockWindow);
  630. if (oldFocus)
  631. oldFocus->setFocus();
  632. if (dockWindow->place() == Q3DockWindow::OutsideDock)
  633. dockWindow->raise();
  634. if(dockWindow->opaqueMoving())
  635. releaseMouse();
  636. if (!mousePressed)
  637. return;
  638. dockWindow->endRectDraw(!opaque);
  639. mousePressed = false;
  640. if (!hadDblClick)
  641. dockWindow->updatePosition(e->globalPos());
  642. if (opaque) {
  643. dockWindow->horHandle->mousePressed = false;
  644. dockWindow->verHandle->mousePressed = false;
  645. }
  646. if (dockWindow->parentWidget())
  647. QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
  648. }
  649. void Q3DockWindowTitleBar::resizeEvent(QResizeEvent *e)
  650. {
  651. updateGui();
  652. Q3TitleBar::resizeEvent(e);
  653. }
  654. void Q3DockWindowTitleBar::updateGui()
  655. {
  656. if (dockWindow->isCloseEnabled()) {
  657. setFakeWindowFlags(fakeWindowFlags() | Qt::WStyle_SysMenu);
  658. } else {
  659. setFakeWindowFlags(fakeWindowFlags() & ~Qt::WStyle_SysMenu);
  660. }
  661. }
  662. void Q3DockWindowTitleBar::mouseDoubleClickEvent(QMouseEvent *)
  663. {
  664. emit doubleClicked();
  665. hadDblClick = true;
  666. if (dockWindow->parentWidget())
  667. QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
  668. }
  669. /*!
  670. \class Q3DockWindow
  671. \brief The Q3DockWindow class provides a widget which can be docked
  672. inside a Q3DockArea or floated as a top level window on the
  673. desktop.
  674. \compat
  675. This class handles moving, resizing, docking and undocking dock
  676. windows. Q3ToolBar is a subclass of Q3DockWindow so the
  677. functionality provided for dock windows is available with the same
  678. API for toolbars.
  679. \img qmainwindow-qdockareas.png Q3DockWindows in a Q3DockArea
  680. \caption Two Q3DockWindows (\l{Q3ToolBar}s) in a \l Q3DockArea
  681. \img qdockwindow.png A Q3DockWindow
  682. \caption A Floating Q3DockWindow
  683. If the user drags the dock window into the dock area the dock
  684. window will be docked. If the user drags the dock area outside any
  685. dock areas the dock window will be undocked (floated) and will
  686. become a top level window. Double clicking a floating dock
  687. window's title bar will dock the dock window to the last dock area
  688. it was docked in. Double clicking a docked dock window's handle
  689. will undock (float) the dock window.
  690. \omit
  691. Single clicking a docked dock window's handle will minimize the
  692. dock window (only its handle will appear, below the menu bar).
  693. Single clicking the minimized handle will restore the dock window
  694. to the last dock area that it was docked in.
  695. \endomit
  696. If the user clicks the close button (which appears on floating
  697. dock windows by default) the dock window will disappear. You can
  698. control whether or not a dock window has a close button with
  699. setCloseMode().
  700. Q3MainWindow provides four dock areas (top, left, right and bottom)
  701. which can be used by dock windows. For many applications using the
  702. dock areas provided by Q3MainWindow is sufficient. (See the \l
  703. Q3DockArea documentation if you want to create your own dock
  704. areas.) In Q3MainWindow a right-click popup menu (the dock window
  705. menu) is available which lists dock windows and can be used to
  706. show or hide them. (The popup menu only lists dock windows that
  707. have a \link QWidget::setWindowTitle() caption\endlink.)
  708. When you construct a dock window you \e must pass it a Q3DockArea
  709. or a Q3MainWindow as its parent if you want it docked. Pass 0 for
  710. the parent if you want it floated.
  711. \snippet doc/src/snippets/code/src_qt3support_widgets_q3dockwindow.cpp 0
  712. In the example above we create a new Q3ToolBar in the constructor
  713. of a Q3MainWindow subclass (so that the \e this pointer points to
  714. the Q3MainWindow). By default the toolbar will be added to the \c
  715. Top dock area, but we've moved it to the \c Left dock area.
  716. A dock window is often used to contain a single widget. In these
  717. cases the widget can be set by calling setWidget(). If you're
  718. constructing a dock window that contains multiple widgets, e.g. a
  719. toolbar, arrange the widgets within a box layout inside the dock
  720. window. To do this use the boxLayout() function to get a pointer
  721. to the dock window's box layout, then add widgets to the layout
  722. using the box layout's QBoxLayout::addWidget() function. The dock
  723. window will dynamically set the orientation of the layout to be
  724. vertical or horizontal as necessary, although you can control this
  725. yourself with setOrientation().
  726. Although a common use of dock windows is for toolbars, they can be
  727. used with any widgets. When using larger
  728. widgets it may make sense for the dock window to be resizable by
  729. calling setResizeEnabled(). Resizable dock windows are given
  730. splitter-like handles to allow the user to resize them within
  731. their dock area. When resizable dock windows are undocked they
  732. become top level windows and can be resized like any other top
  733. level windows, e.g. by dragging a corner or edge.
  734. Qt::Dock windows can be docked and undocked using dock() and undock().
  735. A dock window's orientation can be set with setOrientation(). You
  736. can also use Q3DockArea::moveDockWindow(). If you're using a
  737. Q3MainWindow, Q3MainWindow::moveDockWindow() and
  738. Q3MainWindow::removeDockWindow() are available.
  739. A dock window can have some preferred settings, for example, you
  740. can set a preferred offset from the left edge (or top edge for
  741. vertical dock areas) of the dock area using setOffset(). If you'd
  742. prefer a dock window to start on a new line when it is docked use
  743. setNewLine(). The setFixedExtentWidth() and setFixedExtentHeight()
  744. functions can be used to define the dock window's preferred size,
  745. and the setHorizontallyStretchable() and setVerticallyStretchable()
  746. functions set whether the dock window can be stretched or not.
  747. Dock windows can be moved by default, but this can be changed with
  748. setMovingEnabled(). When a dock window is moved it is shown as a
  749. rectangular outline, but it can be shown normally using
  750. setOpaqueMoving().
  751. When a dock window's visibility changes, i.e. it is shown or
  752. hidden, the visibilityChanged() signal is emitted. When a dock
  753. window is docked, undocked or moved inside the dock area the
  754. placeChanged() signal is emitted.
  755. */
  756. /*!
  757. \enum Q3DockWindow::Place
  758. This enum specifies the possible locations for a Q3DockWindow:
  759. \value InDock Inside a Q3DockArea.
  760. \value OutsideDock Floating as a top level window on the desktop.
  761. */
  762. /*!
  763. \enum Q3DockWindow::CloseMode
  764. This enum type specifies when (if ever) a dock window has a close
  765. button.
  766. \value Never The dock window never has a close button and cannot
  767. be closed by the user.
  768. \value Docked The dock window has a close button only when
  769. docked.
  770. \value Undocked The dock window has a close button only when
  771. floating.
  772. \value Always The dock window always has a close button.
  773. \omit
  774. Note that dock windows can always be minimized if the user clicks
  775. their dock window handle when they are docked.
  776. \endomit
  777. */
  778. /*!
  779. \fn void Q3DockWindow::setHorizontalStretchable(bool b)
  780. If \a b is true the dock window is set to be horizontally
  781. stretchable.
  782. */
  783. /*!
  784. \fn void Q3DockWindow::setVerticalStretchable(bool b)
  785. If \a b is true the dock window is set to be vertically
  786. stretchable.
  787. */
  788. /*!
  789. \fn bool Q3DockWindow::isHorizontalStretchable() const
  790. Returns true if the dock window can be stretched horizontally;
  791. otherwise returns false.
  792. */
  793. /*!
  794. \fn bool Q3DockWindow::isVerticalStretchable() const
  795. Returns true if the dock window can be stretched vertically;
  796. otherwise returns false.
  797. */
  798. /*!
  799. \fn void Q3DockWindow::orientationChanged(Qt::Orientation o)
  800. This signal is emitted when the orientation of the dock window is
  801. changed. The new orientation is \a o.
  802. */
  803. /*!
  804. \fn void Q3DockWindow::placeChanged(Q3DockWindow::Place p)
  805. This signal is emitted when the dock window is docked (\a p is \c
  806. InDock), undocked (\a p is \c OutsideDock) or moved inside the
  807. the dock area.
  808. \sa Q3DockArea::moveDockWindow(), Q3DockArea::removeDockWindow(),
  809. Q3MainWindow::moveDockWindow(), Q3MainWindow::removeDockWindow()
  810. */
  811. /*!
  812. \fn void Q3DockWindow::visibilityChanged(bool visible)
  813. This signal is emitted when the visibility of the dock window
  814. relatively to its dock area is changed. If \a visible is true, the
  815. Q3DockWindow is now visible to the dock area, otherwise it has been
  816. hidden.
  817. A dock window can be hidden if it has a close button which the
  818. user has clicked. In the case of a Q3MainWindow a dock window can
  819. have its visibility changed (hidden or shown) by clicking its name
  820. in the dock window menu that lists the Q3MainWindow's dock windows.
  821. */
  822. /*!
  823. \fn Q3DockArea *Q3DockWindow::area() const
  824. Returns the dock area in which this dock window is docked, or 0 if
  825. the dock window is floating.
  826. */
  827. /*!
  828. \property Q3DockWindow::place
  829. \brief the location where the dock window is placed
  830. This is either \c InDock or \c OutsideDock.
  831. \sa Q3DockArea::moveDockWindow(), Q3DockArea::removeDockWindow(),
  832. Q3MainWindow::moveDockWindow(), Q3MainWindow::removeDockWindow()
  833. */
  834. /*!
  835. Constructs a Q3DockWindow with parent \a parent, called \a name and
  836. with widget flags \a f.
  837. */
  838. Q3DockWindow::Q3DockWindow(QWidget* parent, const char* name, Qt::WindowFlags f)
  839. : Q3Frame(parent, name, f | Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder)
  840. {
  841. curPlace = InDock;
  842. isToolbar = false;
  843. init();
  844. }
  845. /*!
  846. Constructs a Q3DockWindow with parent \a parent, called \a name and
  847. with widget flags \a f.
  848. If \a p is \c InDock, the dock window is docked into a dock area
  849. and \a parent \e must be a Q3DockArea or a Q3MainWindow. If the \a
  850. parent is a Q3MainWindow the dock window will be docked in the main
  851. window's \c Top dock area.
  852. If \a p is \c OutsideDock, the dock window is created as a floating
  853. window.
  854. We recommend creating the dock area \c InDock with a Q3MainWindow
  855. as parent then calling Q3MainWindow::moveDockWindow() to move the
  856. dock window where you want it.
  857. */
  858. Q3DockWindow::Q3DockWindow(Place p, QWidget *parent, const char *name, Qt::WindowFlags f)
  859. : Q3Frame(parent, name, f | Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder)
  860. {
  861. curPlace = p;
  862. isToolbar = false;
  863. init();
  864. }
  865. /*! \internal
  866. */
  867. Q3DockWindow::Q3DockWindow(Place p, QWidget *parent, const char *name, Qt::WindowFlags f, bool toolbar)
  868. : Q3Frame(parent, name, f | Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder)
  869. {
  870. curPlace = p;
  871. isToolbar = toolbar;
  872. init();
  873. }
  874. class Q3DockWindowGridLayout : public QGridLayout
  875. {
  876. public:
  877. Q3DockWindowGridLayout(QWidget *parent, int nRows, int nCols)
  878. : QGridLayout(parent, nRows, nCols) {};
  879. Qt::Orientations expandingDirections() const
  880. {
  881. return 0;
  882. }
  883. };
  884. void Q3DockWindow::init()
  885. {
  886. wid = 0;
  887. rubberBand = 0;
  888. dockArea = 0;
  889. tmpDockArea = 0;
  890. resizeEnabled = false;
  891. moveEnabled = true;
  892. nl = false;
  893. opaque = default_opaque;
  894. cMode = Never;
  895. offs = 0;
  896. fExtent = QSize(-1, -1);
  897. dockWindowData = 0;
  898. lastPos = QPoint(-1, -1);
  899. lastSize = QSize(-1, -1);
  900. stretchable[Qt::Horizontal] = false;
  901. stretchable[Qt::Vertical] = false;
  902. widgetResizeHandler = new QWidgetResizeHandler(this);
  903. widgetResizeHandler->setMovingEnabled(false);
  904. titleBar = new Q3DockWindowTitleBar(this);
  905. verHandle = new Q3DockWindowHandle(this);
  906. verHandle->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
  907. horHandle = new Q3DockWindowHandle(this);
  908. horHandle->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
  909. vHandleLeft = new Q3DockWindowResizeHandle(Qt::Vertical, this, this, "vert. handle");
  910. vHandleRight = new Q3DockWindowResizeHandle(Qt::Vertical, this, this, "vert. handle");
  911. hHandleTop = new Q3DockWindowResizeHandle(Qt::Horizontal, this, this, "horz. handle");
  912. hHandleBottom = new Q3DockWindowResizeHandle(Qt::Horizontal, this, this, "horz. handle");
  913. // Creating inner layout
  914. hbox = new QVBoxLayout();
  915. vbox = new QHBoxLayout();
  916. childBox = new QBoxLayout(QBoxLayout::LeftToRight);
  917. vbox->addSpacing(2);
  918. vbox->addWidget(verHandle);
  919. vbox->addStretch(0);
  920. vbox->addLayout(childBox, 1);
  921. vbox->addStretch(0);
  922. hbox->setResizeMode(QLayout::FreeResize);
  923. hbox->setMargin(isResizeEnabled() || curPlace == OutsideDock ? 2 : 0);
  924. hbox->setSpacing(1);
  925. hbox->addWidget(titleBar);
  926. hbox->addWidget(horHandle);
  927. hbox->addLayout(vbox);
  928. // Set up the initial handle layout for Qt::Vertical
  929. // Handle layout will change on calls to setOrienation()
  930. QGridLayout *glayout = new Q3DockWindowGridLayout(this, 3, 3);
  931. glayout->setResizeMode(QLayout::Minimum);
  932. glayout->addMultiCellWidget(hHandleTop, 0, 0, 1, 1);
  933. glayout->addMultiCellWidget(hHandleBottom, 2, 2, 1, 1);
  934. glayout->addMultiCellWidget(vHandleLeft, 0, 2, 0, 0);
  935. glayout->addMultiCellWidget(vHandleRight, 0, 2, 2, 2);
  936. glayout->addLayout(hbox, 1, 1);
  937. glayout->setRowStretch(1, 1);
  938. glayout->setColStretch(1, 1);
  939. hHandleBottom->hide();
  940. vHandleRight->hide();
  941. hHandleTop->hide();
  942. vHandleLeft->hide();
  943. setFrameStyle(Q3Frame::StyledPanel | Q3Frame::Raised);
  944. setLineWidth(2);
  945. if (parentWidget())
  946. parentWidget()->installEventFilter(this);
  947. QWidget *mw = parentWidget();
  948. Q3DockArea *da = qobject_cast<Q3DockArea*>(parentWidget());
  949. if (da) {
  950. if (curPlace == InDock)
  951. da->moveDockWindow(this);
  952. mw = da->parentWidget();
  953. }
  954. if (qobject_cast<Q3MainWindow*>(mw)) {
  955. if (place() == InDock) {
  956. Qt::Dock myDock = Qt::DockTop;
  957. // make sure we put the window in the correct dock.
  958. if (dockArea) {
  959. Q3MainWindow *mainw = (Q3MainWindow*)mw;
  960. // I'm not checking if it matches the top because I've
  961. // done the assignment to it above.
  962. if (dockArea == mainw->leftDock())
  963. myDock = Qt::DockLeft;
  964. else if (dockArea == mainw->rightDock())
  965. myDock = Qt::DockRight;
  966. else if (dockArea == mainw->bottomDock())
  967. myDock = Qt::DockBottom;
  968. }
  969. ((Q3MainWindow*)mw)->addDockWindow(this, myDock);
  970. }
  971. moveEnabled = ((Q3MainWindow*)mw)->dockWindowsMovable();
  972. opaque = ((Q3MainWindow*)mw)->opaqueMoving();
  973. }
  974. updateGui();
  975. connect(titleBar, SIGNAL(doubleClicked()), this, SLOT(dock()));
  976. connect(verHandle, SIGNAL(doubleClicked()), this, SLOT(undock()));
  977. connect(horHandle, SIGNAL(doubleClicked()), this, SLOT(undock()));
  978. connect(this, SIGNAL(orientationChanged(Qt::Orientation)),
  979. this, SLOT(setOrientation(Qt::Orientation)));
  980. }
  981. /*!
  982. Sets the orientation of the dock window to \a o. The orientation
  983. is propagated to the layout boxLayout().
  984. \warning All undocked Q3ToolBars will always have a horizontal orientation.
  985. */
  986. void Q3DockWindow::setOrientation(Qt::Orientation o)
  987. {
  988. QGridLayout *glayout = (QGridLayout*)layout();
  989. glayout->removeWidget(hHandleTop);
  990. glayout->removeWidget(hHandleBottom);
  991. glayout->removeWidget(vHandleLeft);
  992. glayout->removeWidget(vHandleRight);
  993. if (o == Qt::Horizontal) {
  994. // Set up the new layout as
  995. // 3 3 3 1 = vHandleLeft 4 = hHandleBottom
  996. // 1 X 2 2 = vHandleRight X = Inner Layout
  997. // 4 4 4 3 = hHandleTop
  998. glayout->addMultiCellWidget(hHandleTop, 0, 0, 0, 2);
  999. glayout->addMultiCellWidget(hHandleBottom, 2, 2, 0, 2);
  1000. glayout->addMultiCellWidget(vHandleLeft, 1, 1, 0, 0);
  1001. glayout->addMultiCellWidget(vHandleRight, 1, 1, 2, 2);
  1002. } else {
  1003. // Set up the new layout as
  1004. // 1 3 2 1 = vHandleLeft 4 = hHandleBottom
  1005. // 1 X 2 2 = vHandleRight X = Inner Layout
  1006. // 1 4 2 3 = hHandleTop
  1007. glayout->addMultiCellWidget(hHandleTop, 0, 0, 1, 1);
  1008. glayout->addMultiCellWidget(hHandleBottom, 2, 2, 1, 1);
  1009. glayout->addMultiCellWidget(vHandleLeft, 0, 2, 0, 0);
  1010. glayout->addMultiCellWidget(vHandleRight, 0, 2, 2, 2);
  1011. }
  1012. boxLayout()->setDirection(o == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom);
  1013. QApplication::sendPostedEvents(this, QEvent::LayoutHint);
  1014. QEvent *e = new QEvent(QEvent::LayoutHint);
  1015. QApplication::postEvent(this, e);
  1016. }
  1017. /*!
  1018. Destroys the dock window and its child widgets.
  1019. */
  1020. Q3DockWindow::~Q3DockWindow()
  1021. {
  1022. qApp->removeEventFilter(this);
  1023. if (area())
  1024. area()->removeDockWindow(this, false, false);
  1025. Q3DockArea *a = area();
  1026. if (!a && dockWindowData)
  1027. a = ((Q3DockArea::DockWindowData*)dockWindowData)->area;
  1028. Q3MainWindow *mw = a ? qobject_cast<Q3MainWindow*>(a->parentWidget()) : 0;
  1029. if (mw)
  1030. mw->removeDockWindow(this);
  1031. delete (Q3DockArea::DockWindowData*)dockWindowData;
  1032. }
  1033. /*! \reimp
  1034. */
  1035. void Q3DockWindow::resizeEvent(QResizeEvent *e)
  1036. {
  1037. Q3Frame::resizeEvent(e);
  1038. updateGui();
  1039. }
  1040. void Q3DockWindow::swapRect(QRect &r, Qt::Orientation o, const QPoint &offset, Q3DockArea *)
  1041. {
  1042. r.setSize(QSize(r.height(), r.width()));
  1043. bool reverse = QApplication::reverseLayout();
  1044. if (o == Qt::Horizontal)
  1045. r.moveBy(-r.width()/2, 0);
  1046. else
  1047. r.moveBy(reverse ? - r.width() : 0, -r.height() / 2 );
  1048. r.moveBy(offset.x(), offset.y());
  1049. }
  1050. QWidget *Q3DockWindow::areaAt(const QPoint &gp)
  1051. {
  1052. QWidget *w = qApp->widgetAt(gp);
  1053. if (w && (w == this || w == titleBar) && parentWidget())
  1054. w = parentWidget()->childAt(parentWidget()->mapFromGlobal(gp));
  1055. while (w) {
  1056. if (qobject_cast<Q3DockArea*>(w)) {
  1057. Q3DockArea *a = (Q3DockArea*)w;
  1058. if (a->isDockWindowAccepted(this))
  1059. return w;
  1060. }
  1061. if (qobject_cast<Q3MainWindow*>(w)) {
  1062. Q3MainWindow *mw = (Q3MainWindow*)w;
  1063. Q3DockArea *a = mw->dockingArea(mw->mapFromGlobal(gp));
  1064. if (a && a->isDockWindowAccepted(this))
  1065. return a;
  1066. }
  1067. w = w->isWindow() ? 0 : (QWidget *)w->parent();
  1068. }
  1069. return 0;
  1070. }
  1071. void Q3DockWindow::handleMove(const QPoint &pos, const QPoint &gp, bool drawRect)
  1072. {
  1073. if (!rubberBand)
  1074. return;
  1075. currRect = QRect(realWidgetPos(this), size());
  1076. QWidget *w = areaAt(gp);
  1077. if (titleBar->ctrlDown || horHandle->ctrlDown || verHandle->ctrlDown)
  1078. w = 0;
  1079. currRect.moveBy(pos.x(), pos.y());
  1080. if (!qobject_cast<Q3DockArea*>(w)) {
  1081. if (startOrientation != Qt::Horizontal && qobject_cast<Q3ToolBar*>(this))
  1082. swapRect(currRect, Qt::Horizontal, startOffset, (Q3DockArea*)w);
  1083. if (drawRect) {
  1084. rubberBand->setGeometry(currRect);
  1085. } else {
  1086. QPoint mp(mapToGlobal(pos));
  1087. if(place() == InDock) {
  1088. undock();
  1089. if(titleBar) {
  1090. mp = QPoint(titleBar->width() / 2, titleBar->height() / 2);
  1091. QMouseEvent me(QEvent::MouseButtonPress, mp, Qt::LeftButton, 0);
  1092. QApplication::sendEvent(titleBar, &me);
  1093. mp = titleBar->mapToGlobal(mp);
  1094. }
  1095. }
  1096. move(mp);
  1097. }
  1098. state = OutsideDock;
  1099. return;
  1100. }
  1101. Q3DockArea *area = (Q3DockArea*)w;
  1102. if(area->isVisible()) {
  1103. state = InDock;
  1104. Qt::Orientation o = (area ? area->orientation() :
  1105. (boxLayout()->direction() == QBoxLayout::LeftToRight ||
  1106. boxLayout()->direction() == QBoxLayout::RightToLeft ?
  1107. Qt::Horizontal : Qt::Vertical));
  1108. if (startOrientation != o)
  1109. swapRect(currRect, o, startOffset, area);
  1110. if (drawRect) {
  1111. rubberBand->setGeometry(currRect);
  1112. }
  1113. tmpDockArea = area;
  1114. }
  1115. }
  1116. void Q3DockWindow::updateGui()
  1117. {
  1118. if (curPlace == OutsideDock) {
  1119. hbox->setMargin(2);
  1120. horHandle->hide();
  1121. verHandle->hide();
  1122. if (moveEnabled)
  1123. titleBar->show();
  1124. else
  1125. titleBar->hide();
  1126. titleBar->updateGui();
  1127. hHandleTop->hide();
  1128. vHandleLeft->hide();
  1129. hHandleBottom->hide();
  1130. vHandleRight->hide();
  1131. setLineWidth(2);
  1132. widgetResizeHandler->setActive(isResizeEnabled());
  1133. } else {
  1134. hbox->setMargin(0);
  1135. titleBar->hide();
  1136. if (orientation() == Qt::Horizontal) {
  1137. horHandle->hide();
  1138. if (moveEnabled)
  1139. verHandle->show();
  1140. else
  1141. verHandle->hide();
  1142. #ifdef Q_WS_MAC
  1143. if(horHandle->mousePressed) {
  1144. horHandle->mousePressed = false;
  1145. verHandle->mousePressed = true;
  1146. verHandle->grabMouse();
  1147. }
  1148. #endif
  1149. verHandle->updateGui();
  1150. } else {
  1151. if (moveEnabled)
  1152. horHandle->show();
  1153. else
  1154. horHandle->hide();
  1155. horHandle->updateGui();
  1156. #ifdef Q_WS_MAC
  1157. if(verHandle->mousePressed) {
  1158. verHandle->mousePressed = false;
  1159. horHandle->mousePressed = true;
  1160. horHandle->grabMouse();
  1161. }
  1162. #endif
  1163. verHandle->hide();
  1164. }
  1165. if (isResizeEnabled()) {
  1166. if (orientation() == Qt::Horizontal) {
  1167. hHandleBottom->raise();
  1168. hHandleTop->raise();
  1169. } else {
  1170. vHandleRight->raise();
  1171. vHandleLeft->raise();
  1172. }
  1173. if (area()) {
  1174. if (orientation() == Qt::Horizontal) {
  1175. if (area()->handlePosition() == Q3DockArea::Normal) {
  1176. hHandleBottom->show();
  1177. hHandleTop->hide();
  1178. } else {
  1179. hHandleTop->show();
  1180. hHandleBottom->hide();
  1181. }
  1182. if (!area()->isLastDockWindow(this))
  1183. vHandleRight->show();
  1184. else
  1185. vHandleRight->hide();
  1186. vHandleLeft->hide();
  1187. } else {
  1188. if ((area()->handlePosition() == Q3DockArea::Normal) != QApplication::reverseLayout()) {
  1189. vHandleRight->show();
  1190. vHandleLeft->hide();
  1191. } else {
  1192. vHandleLeft->show();
  1193. vHandleRight->hide();
  1194. }
  1195. if (!area()->isLastDockWindow(this))
  1196. hHandleBottom->show();
  1197. else
  1198. hHandleBottom->hide();
  1199. hHandleTop->hide();
  1200. }
  1201. }
  1202. }
  1203. #ifndef Q_OS_WINCE
  1204. if (moveEnabled)
  1205. setLineWidth(1);
  1206. else
  1207. setLineWidth(0);
  1208. #endif
  1209. widgetResizeHandler->setActive(false);
  1210. }
  1211. }
  1212. void Q3DockWindow::updatePosition(const QPoint &globalPos)
  1213. {
  1214. if (curPlace == OutsideDock && state == InDock)
  1215. lastSize = size();
  1216. bool doAdjustSize = curPlace != state && state == OutsideDock;
  1217. bool doUpdate = true;
  1218. bool doOrientationChange = true;
  1219. if (state != curPlace && state == InDock) {
  1220. doUpdate = false;
  1221. curPlace = state;
  1222. updateGui();
  1223. QApplication::sendPostedEvents();
  1224. }
  1225. Qt::Orientation oo = orientation();
  1226. if (state == InDock) {
  1227. if (tmpDockArea) {
  1228. bool differentDocks = false;
  1229. if (dockArea && dockArea != tmpDockArea) {
  1230. differentDocks = true;
  1231. delete (Q3DockArea::DockWindowData*)dockWindowData;
  1232. dockWindowData = dockArea->dockWindowData(this);
  1233. dockArea->removeDockWindow(this, false, false);
  1234. }
  1235. dockArea = tmpDockArea;
  1236. if (differentDocks) {
  1237. if (doUpdate) {
  1238. doUpdate = false;
  1239. curPlace = state;
  1240. updateGui();
  1241. }
  1242. emit orientationChanged(tmpDockArea->orientation());
  1243. doOrientationChange = false;
  1244. } else {
  1245. updateGui();
  1246. }
  1247. dockArea->moveDockWindow(this, globalPos, currRect, startOrientation != oo);
  1248. }
  1249. } else {
  1250. if (dockArea) {
  1251. Q3MainWindow *mw = (Q3MainWindow*)dockArea->parentWidget();
  1252. if (qobject_cast<Q3MainWindow*>(mw) &&
  1253. (!mw->isDockEnabled(Qt::DockTornOff) ||
  1254. !mw->isDockEnabled(this, Qt::DockTornOff)))
  1255. return;
  1256. delete (Q3DockArea::DockWindowData*)dockWindowData;
  1257. dockWindowData = dockArea->dockWindowData(this);
  1258. dockArea->removeDockWindow(this, true,
  1259. startOrientation != Qt::Horizontal && qobject_cast<Q3ToolBar*>(this));
  1260. }
  1261. dockArea = 0;
  1262. QPoint topLeft = currRect.topLeft();
  1263. QRect screen = qApp->desktop()->availableGeometry(topLeft);
  1264. if (!screen.contains(topLeft)) {
  1265. topLeft.setY(qMax(topLeft.y(), screen.top()));
  1266. topLeft.setY(qMin(topLeft.y(), screen.bottom()-height()));
  1267. topLeft.setX(qMax(topLeft.x(), screen.left()));
  1268. topLeft.setX(qMin(topLeft.x(), screen.right()-width()));
  1269. }
  1270. move(topLeft);
  1271. }
  1272. if (curPlace == InDock && state == OutsideDock && !qobject_cast<Q3ToolBar*>(this)) {
  1273. if (lastSize != QSize(-1, -1))
  1274. resize(lastSize);
  1275. }
  1276. if (doUpdate) {
  1277. curPlace = state;
  1278. updateGui();
  1279. }
  1280. if (doOrientationChange)
  1281. emit orientationChanged(orientation());
  1282. tmpDockArea = 0;
  1283. if (doAdjustSize) {
  1284. QApplication::sendPostedEvents(this, QEvent::LayoutHint);
  1285. if (qobject_cast<Q3ToolBar*>(this))
  1286. adjustSize();
  1287. if (lastSize == QSize(-1, -1))
  1288. setAttribute(Qt::WA_Resized, false); // Ensures size is recalculated (non-opaque).
  1289. show();
  1290. if (parentWidget() && isWindow())
  1291. parentWidget()->setActiveWindow();
  1292. }
  1293. emit placeChanged(curPlace);
  1294. }
  1295. /*!
  1296. Sets the dock window's main widget to \a w.
  1297. \sa boxLayout()
  1298. */
  1299. void Q3DockWindow::setWidget(QWidget *w)
  1300. {
  1301. wid = w;
  1302. boxLayout()->addWidget(w);
  1303. updateGui();
  1304. }
  1305. /*!
  1306. Returns the dock window's main widget.
  1307. \sa setWidget()
  1308. */
  1309. QWidget *Q3DockWindow::widget() const
  1310. {
  1311. return wid;
  1312. }
  1313. void Q3DockWindow::startRectDraw(const QPoint &so, bool drawRect)
  1314. {
  1315. state = place();
  1316. if (rubberBand)
  1317. endRectDraw(!opaque);
  1318. rubberBand = new QRubberBand(QRubberBand::Rectangle);
  1319. currRect = QRect(realWidgetPos(this), size());
  1320. if (drawRect) {
  1321. rubberBand->setGeometry(currRect);
  1322. }
  1323. startOrientation = orientation();
  1324. startOffset = mapFromGlobal(so);
  1325. rubberBand->show();
  1326. }
  1327. void Q3DockWindow::endRectDraw(bool)
  1328. {
  1329. delete rubberBand;
  1330. rubberBand = 0;
  1331. }
  1332. /*!
  1333. \reimp
  1334. */
  1335. void Q3DockWindow::drawFrame(QPainter *p)
  1336. {
  1337. if (place() == InDock) {
  1338. Q3Frame::drawFrame(p);
  1339. return;
  1340. }
  1341. QStyleOptionFrame opt;
  1342. opt.rect = rect();
  1343. opt.palette = palette();
  1344. opt.state = QStyle::State_None;
  1345. if (titleBar->isActive())
  1346. opt.state |= QStyle::State_Active;
  1347. opt.lineWidth = lineWidth();
  1348. opt.midLineWidth = midLineWidth();
  1349. style()->drawPrimitive(QStyle::PE_FrameWindow, &opt, p, this);
  1350. }
  1351. /*!
  1352. \reimp
  1353. */
  1354. void Q3DockWindow::drawContents(QPainter *p)
  1355. {
  1356. // This is only used by the PocketPC style. We probably need to revist later.…

Large files are truncated, but you can click here to view the full file