source: trunk/src/gui/graphicsview/qgraphicswidget.cpp@ 809

Last change on this file since 809 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 75.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qglobal.h"
43
44#ifndef QT_NO_GRAPHICSVIEW
45
46#include "qgraphicswidget.h"
47#include "qgraphicswidget_p.h"
48#include "qgraphicslayout.h"
49#include "qgraphicslayout_p.h"
50#include "qgraphicsscene.h"
51#include "qgraphicssceneevent.h"
52
53#ifndef QT_NO_ACTION
54#include <private/qaction_p.h>
55#endif
56#include <private/qapplication_p.h>
57#include <private/qgraphicsscene_p.h>
58#ifndef QT_NO_SHORTCUT
59#include <private/qshortcutmap_p.h>
60#endif
61#include <QtCore/qmutex.h>
62#include <QtGui/qapplication.h>
63#include <QtGui/qgraphicsview.h>
64#include <QtGui/qgraphicsproxywidget.h>
65#include <QtGui/qpalette.h>
66#include <QtGui/qstyleoption.h>
67
68#include <qdebug.h>
69
70QT_BEGIN_NAMESPACE
71
72/*!
73 \class QGraphicsWidget
74 \brief The QGraphicsWidget class is the base class for all widget
75 items in a QGraphicsScene.
76 \since 4.4
77 \ingroup graphicsview-api
78
79 QGraphicsWidget is an extended base item that provides extra functionality
80 over QGraphicsItem. It is similar to QWidget in many ways:
81
82 \list
83 \o Provides a \l palette, a \l font and a \l style().
84 \o Has a defined geometry().
85 \o Supports layouts with setLayout() and layout().
86 \o Supports shortcuts and actions with grabShortcut() and insertAction()
87 \endlist
88
89 Unlike QGraphicsItem, QGraphicsWidget is not an abstract class; you can
90 create instances of a QGraphicsWidget without having to subclass it.
91 This approach is useful for widgets that only serve the purpose of
92 organizing child widgets into a layout.
93
94 QGraphicsWidget can be used as a base item for your own custom item if
95 you require advanced input focus handling, e.g., tab focus and activation, or
96 layouts.
97
98 Since QGraphicsWidget resembles QWidget and has similar API, it is
99 easier to port a widget from QWidget to QGraphicsWidget, instead of
100 QGraphicsItem.
101
102 \note QWidget-based widgets can be directly embedded into a
103 QGraphicsScene using QGraphicsProxyWidget.
104
105 Noticeable differences between QGraphicsWidget and QWidget are:
106
107 \table
108 \header \o QGraphicsWidget
109 \o QWidget
110 \row \o Coordinates and geometry are defined with qreals (doubles or
111 floats, depending on the platform).
112 \o QWidget uses integer geometry (QPoint, QRect).
113 \row \o The widget is already visible by default; you do not have to
114 call show() to display the widget.
115 \o QWidget is hidden by default until you call show().
116 \row \o A subset of widget attributes are supported.
117 \o All widget attributes are supported.
118 \row \o A top-level item's style defaults to QGraphicsScene::style
119 \o A top-level widget's style defaults to QApplication::style
120 \row \o Graphics View provides a custom drag and drop framework, different
121 from QWidget.
122 \o Standard drag and drop framework.
123 \row \o Widget items do not support modality.
124 \o Full modality support.
125 \endtable
126
127 QGraphicsWidget supports a subset of Qt's widget attributes,
128 (Qt::WidgetAttribute), as shown in the table below. Any attributes not
129 listed in this table are unsupported, or otherwise unused.
130
131 \table
132 \header \o Widget Attribute \o Usage
133 \row \o Qt::WA_SetLayoutDirection
134 \o Set by setLayoutDirection(), cleared by
135 unsetLayoutDirection(). You can test this attribute to
136 check if the widget has been explicitly assigned a
137 \l{QGraphicsWidget::layoutDirection()}
138 {layoutDirection}. If the attribute is not set, the
139 \l{QGraphicsWidget::layoutDirection()}
140 {layoutDirection()} is inherited.
141 \row \o Qt::WA_RightToLeft
142 \o Toggled by setLayoutDirection(). Inherited from the
143 parent/scene. If set, the widget's layout will order
144 horizontally arranged widgets from right to left.
145 \row \o Qt::WA_SetStyle
146 \o Set and cleared by setStyle(). If this attribute is
147 set, the widget has been explicitly assigned a style.
148 If it is unset, the widget will use the scene's or the
149 application's style.
150 \row \o Qt::WA_Resized
151 \o Set by setGeometry() and resize().
152 \row \o Qt::WA_SetPalette
153 \o Set by setPalette().
154 \row \o Qt::WA_SetFont
155 \o Set by setPalette().
156 \row \o Qt::WA_WindowPropagation
157 \o Enables propagation to window widgets.
158 \endtable
159
160 Although QGraphicsWidget inherits from both QObject and QGraphicsItem,
161 you should use the functions provided by QGraphicsItem, \e not QObject, to
162 manage the relationships between parent and child items. These functions
163 control the stacking order of items as well as their ownership.
164
165 \note The QObject::parent() should always return 0 for QGraphicsWidgets,
166 but this policy is not strictly defined.
167
168 \sa QGraphicsProxyWidget, QGraphicsItem, {Widgets and Layouts}
169*/
170
171/*!
172 Constructs a QGraphicsWidget instance. The optional \a parent argument is
173 passed to QGraphicsItem's constructor. The optional \a wFlags argument
174 specifies the widget's window flags (e.g., whether the widget should be a
175 window, a tool, a popup, etc).
176*/
177QGraphicsWidget::QGraphicsWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
178 : QGraphicsObject(*new QGraphicsWidgetPrivate, 0, 0), QGraphicsLayoutItem(0, false)
179{
180 Q_D(QGraphicsWidget);
181 d->init(parent, wFlags);
182}
183
184/*!
185 \internal
186
187 Constructs a new QGraphicsWidget, using \a dd as parent.
188*/
189QGraphicsWidget::QGraphicsWidget(QGraphicsWidgetPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene, Qt::WindowFlags wFlags)
190 : QGraphicsObject(dd, 0, scene), QGraphicsLayoutItem(0, false)
191{
192 Q_D(QGraphicsWidget);
193 d->init(parent, wFlags);
194}
195
196/*
197 \internal
198 \class QGraphicsWidgetStyles
199
200 We use this thread-safe class to maintain a hash of styles for widgets
201 styles. Note that QApplication::style() itself isn't thread-safe, QStyle
202 isn't thread-safe, and we don't have a thread-safe factory for creating
203 the default style, nor cloning a style.
204*/
205class QGraphicsWidgetStyles
206{
207public:
208 QStyle *styleForWidget(const QGraphicsWidget *widget) const
209 {
210 QMutexLocker locker(&mutex);
211 return styles.value(widget, 0);
212 }
213
214 void setStyleForWidget(QGraphicsWidget *widget, QStyle *style)
215 {
216 QMutexLocker locker(&mutex);
217 if (style)
218 styles[widget] = style;
219 else
220 styles.remove(widget);
221 }
222
223private:
224 QMap<const QGraphicsWidget *, QStyle *> styles;
225 mutable QMutex mutex;
226};
227Q_GLOBAL_STATIC(QGraphicsWidgetStyles, widgetStyles)
228
229/*!
230 Destroys the QGraphicsWidget instance.
231*/
232QGraphicsWidget::~QGraphicsWidget()
233{
234 Q_D(QGraphicsWidget);
235#ifndef QT_NO_ACTION
236 // Remove all actions from this widget
237 for (int i = 0; i < d->actions.size(); ++i) {
238 QActionPrivate *apriv = d->actions.at(i)->d_func();
239 apriv->graphicsWidgets.removeAll(this);
240 }
241 d->actions.clear();
242#endif
243
244 if (QGraphicsScene *scn = scene()) {
245 QGraphicsScenePrivate *sceneD = scn->d_func();
246 if (sceneD->tabFocusFirst == this)
247 sceneD->tabFocusFirst = (d->focusNext == this ? 0 : d->focusNext);
248 }
249 d->focusPrev->d_func()->focusNext = d->focusNext;
250 d->focusNext->d_func()->focusPrev = d->focusPrev;
251
252 // Play it really safe
253 d->focusNext = this;
254 d->focusPrev = this;
255
256 clearFocus();
257
258 //we check if we have a layout previously
259 if (d->layout) {
260 QGraphicsLayout *temp = d->layout;
261 foreach (QGraphicsItem * item, childItems()) {
262 // In case of a custom layout which doesn't remove and delete items, we ensure that
263 // the parent layout item does not point to the deleted layout. This code is here to
264 // avoid regression from 4.4 to 4.5, because according to 4.5 docs it is not really needed.
265 if (item->isWidget()) {
266 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
267 if (widget->parentLayoutItem() == d->layout)
268 widget->setParentLayoutItem(0);
269 }
270 }
271 d->layout = 0;
272 delete temp;
273 }
274
275 // Remove this graphics widget from widgetStyles
276 widgetStyles()->setStyleForWidget(this, 0);
277}
278
279/*!
280 \property QGraphicsWidget::size
281 \brief the size of the widget
282
283 Calling resize() resizes the widget to a \a size bounded by minimumSize()
284 and maximumSize(). This property only affects the widget's width and
285 height (e.g., its right and bottom edges); the widget's position and
286 top-left corner remains unaffected.
287
288 Resizing a widget triggers the widget to immediately receive a
289 \l{QEvent::GraphicsSceneResize}{GraphicsSceneResize} event with the
290 widget's old and new size. If the widget has a layout assigned when this
291 event arrives, the layout will be activated and it will automatically
292 update any child widgets's geometry.
293
294 This property does not affect any layout of the parent widget. If the
295 widget itself is managed by a parent layout; e.g., it has a parent widget
296 with a layout assigned, that layout will not activate.
297
298 By default, this property contains a size with zero width and height.
299
300 \sa setGeometry(), QGraphicsSceneResizeEvent, QGraphicsLayout
301*/
302QSizeF QGraphicsWidget::size() const
303{
304 return QGraphicsLayoutItem::geometry().size();
305}
306
307void QGraphicsWidget::resize(const QSizeF &size)
308{
309 setGeometry(QRectF(pos(), size));
310}
311
312/*!
313 \fn void QGraphicsWidget::resize(qreal w, qreal h)
314
315 This convenience function is equivalent to calling resize(QSizeF(w, h)).
316
317 \sa setGeometry(), setTransform()
318*/
319
320/*!
321 \property QGraphicsWidget::sizePolicy
322 \brief the size policy for the widget
323 \sa sizePolicy(), setSizePolicy(), QWidget::sizePolicy()
324*/
325
326/*!
327 \property QGraphicsWidget::geometry
328 \brief the geometry of the widget
329
330 Sets the item's geometry to \a rect. The item's position and size are
331 modified as a result of calling this function. The item is first moved,
332 then resized.
333
334 A side effect of calling this function is that the widget will receive
335 a move event and a resize event. Also, if the widget has a layout
336 assigned, the layout will activate.
337
338 \sa geometry(), resize()
339*/
340void QGraphicsWidget::setGeometry(const QRectF &rect)
341{
342 QGraphicsWidgetPrivate *wd = QGraphicsWidget::d_func();
343 QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr.data();
344 QRectF newGeom;
345 QPointF oldPos = d->geom.topLeft();
346 if (!wd->inSetPos) {
347 setAttribute(Qt::WA_Resized);
348 newGeom = rect;
349 newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
350 .boundedTo(effectiveSizeHint(Qt::MaximumSize)));
351 if (newGeom == d->geom)
352 return;
353
354 // setPos triggers ItemPositionChange, which can adjust position
355 wd->inSetGeometry = 1;
356 setPos(newGeom.topLeft());
357 wd->inSetGeometry = 0;
358 newGeom.moveTopLeft(pos());
359
360 if (newGeom == d->geom)
361 return;
362
363 // Update and prepare to change the geometry (remove from index) if the size has changed.
364 if (wd->scene) {
365 if (rect.topLeft() == d->geom.topLeft()) {
366 prepareGeometryChange();
367 }
368 }
369 }
370
371 // Update the layout item geometry
372 bool moved = oldPos != pos();
373 if (moved) {
374 // Send move event.
375 QGraphicsSceneMoveEvent event;
376 event.setOldPos(oldPos);
377 event.setNewPos(pos());
378 QApplication::sendEvent(this, &event);
379 if (wd->inSetPos) {
380 //set the new pos
381 d->geom.moveTopLeft(pos());
382 return;
383 }
384 }
385 QSizeF oldSize = size();
386 QGraphicsLayoutItem::setGeometry(newGeom);
387
388 // Send resize event
389 bool resized = newGeom.size() != oldSize;
390 if (resized) {
391 QGraphicsSceneResizeEvent re;
392 re.setOldSize(oldSize);
393 re.setNewSize(newGeom.size());
394 QApplication::sendEvent(this, &re);
395 }
396}
397
398/*!
399 \fn QRectF QGraphicsWidget::rect() const
400
401 Returns the item's local rect as a QRectF. This function is equivalent
402 to QRectF(QPointF(), size()).
403
404 \sa setGeometry(), resize()
405*/
406
407/*!
408 \fn void QGraphicsWidget::setGeometry(qreal x, qreal y, qreal w, qreal h)
409
410 This convenience function is equivalent to calling setGeometry(QRectF(
411 \a x, \a y, \a w, \a h)).
412
413 \sa geometry(), resize()
414*/
415
416/*!
417 \property QGraphicsWidget::minimumSize
418 \brief the minimum size of the widget
419
420 \sa setMinimumSize(), minimumSize(), preferredSize, maximumSize
421*/
422
423/*!
424 \property QGraphicsWidget::preferredSize
425 \brief the preferred size of the widget
426
427 \sa setPreferredSize(), preferredSize(), minimumSize, maximumSize
428*/
429
430/*!
431 \property QGraphicsWidget::maximumSize
432 \brief the maximum size of the widget
433
434 \sa setMaximumSize(), maximumSize(), minimumSize, preferredSize
435*/
436
437/*!
438 Sets the widget's contents margins to \a left, \a top, \a right and \a
439 bottom.
440
441 Contents margins are used by the assigned layout to define the placement
442 of subwidgets and layouts. Margins are particularily useful for widgets
443 that constrain subwidgets to only a section of its own geometry. For
444 example, a group box with a layout will place subwidgets inside its frame,
445 but below the title.
446
447 Changing a widget's contents margins will always trigger an update(), and
448 any assigned layout will be activated automatically. The widget will then
449 receive a \l{QEvent::ContentsRectChange}{ContentsRectChange} event.
450
451 \sa getContentsMargins(), setGeometry()
452*/
453void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qreal bottom)
454{
455 Q_D(QGraphicsWidget);
456
457 if (!d->margins && left == 0 && top == 0 && right == 0 && bottom == 0)
458 return;
459 d->ensureMargins();
460 if (left == d->margins[d->Left]
461 && top == d->margins[d->Top]
462 && right == d->margins[d->Right]
463 && bottom == d->margins[d->Bottom])
464 return;
465
466 d->margins[d->Left] = left;
467 d->margins[d->Top] = top;
468 d->margins[d->Right] = right;
469 d->margins[d->Bottom] = bottom;
470
471 if (QGraphicsLayout *l = d->layout)
472 l->invalidate();
473 else
474 updateGeometry();
475
476 QEvent e(QEvent::ContentsRectChange);
477 QApplication::sendEvent(this, &e);
478}
479
480/*!
481 Gets the widget's contents margins. The margins are stored in \a left, \a
482 top, \a right and \a bottom, as pointers to qreals. Each argument can
483 be \e {omitted} by passing 0.
484
485 \sa setContentsMargins()
486*/
487void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
488{
489 Q_D(const QGraphicsWidget);
490 if (left || top || right || bottom)
491 d->ensureMargins();
492 if (left)
493 *left = d->margins[d->Left];
494 if (top)
495 *top = d->margins[d->Top];
496 if (right)
497 *right = d->margins[d->Right];
498 if (bottom)
499 *bottom = d->margins[d->Bottom];
500}
501
502/*!
503 Sets the widget's window frame margins to \a left, \a top, \a right and
504 \a bottom. The default frame margins are provided by the style, and they
505 depend on the current window flags.
506
507 If you would like to draw your own window decoration, you can set your
508 own frame margins to override the default margins.
509
510 \sa unsetWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect()
511*/
512void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom)
513{
514 Q_D(QGraphicsWidget);
515
516 if (!d->windowFrameMargins && left == 0 && top == 0 && right == 0 && bottom == 0)
517 return;
518 d->ensureWindowFrameMargins();
519 bool unchanged =
520 d->windowFrameMargins[d->Left] == left
521 && d->windowFrameMargins[d->Top] == top
522 && d->windowFrameMargins[d->Right] == right
523 && d->windowFrameMargins[d->Bottom] == bottom;
524 if (d->setWindowFrameMargins && unchanged)
525 return;
526 if (!unchanged)
527 prepareGeometryChange();
528 d->windowFrameMargins[d->Left] = left;
529 d->windowFrameMargins[d->Top] = top;
530 d->windowFrameMargins[d->Right] = right;
531 d->windowFrameMargins[d->Bottom] = bottom;
532 d->setWindowFrameMargins = true;
533}
534
535/*!
536 Gets the widget's window frame margins. The margins are stored in \a left,
537 \a top, \a right and \a bottom as pointers to qreals. Each argument can
538 be \e {omitted} by passing 0.
539
540 \sa setWindowFrameMargins(), windowFrameRect()
541*/
542void QGraphicsWidget::getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
543{
544 Q_D(const QGraphicsWidget);
545 if (left || top || right || bottom)
546 d->ensureWindowFrameMargins();
547 if (left)
548 *left = d->windowFrameMargins[d->Left];
549 if (top)
550 *top = d->windowFrameMargins[d->Top];
551 if (right)
552 *right = d->windowFrameMargins[d->Right];
553 if (bottom)
554 *bottom = d->windowFrameMargins[d->Bottom];
555}
556
557/*!
558 Resets the window frame margins to the default value, provided by the style.
559
560 \sa setWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect()
561*/
562void QGraphicsWidget::unsetWindowFrameMargins()
563{
564 Q_D(QGraphicsWidget);
565 if ((d->windowFlags & Qt::Window) && (d->windowFlags & Qt::WindowType_Mask) != Qt::Popup &&
566 (d->windowFlags & Qt::WindowType_Mask) != Qt::ToolTip && !(d->windowFlags & Qt::FramelessWindowHint)) {
567 QStyleOptionTitleBar bar;
568 d->initStyleOptionTitleBar(&bar);
569 QStyle *style = this->style();
570 qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth);
571 qreal titleBarHeight = d->titleBarHeight(bar);
572 setWindowFrameMargins(margin, titleBarHeight, margin, margin);
573 } else {
574 setWindowFrameMargins(0, 0, 0, 0);
575 }
576 d->setWindowFrameMargins = false;
577}
578
579/*!
580 Returns the widget's geometry in parent coordinates including any window
581 frame.
582
583 \sa windowFrameRect(), getWindowFrameMargins(), setWindowFrameMargins()
584*/
585QRectF QGraphicsWidget::windowFrameGeometry() const
586{
587 Q_D(const QGraphicsWidget);
588 return d->windowFrameMargins
589 ? geometry().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top],
590 d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom])
591 : geometry();
592}
593
594/*!
595 Returns the widget's local rect including any window frame.
596
597 \sa windowFrameGeometry(), getWindowFrameMargins(), setWindowFrameMargins()
598*/
599QRectF QGraphicsWidget::windowFrameRect() const
600{
601 Q_D(const QGraphicsWidget);
602 return d->windowFrameMargins
603 ? rect().adjusted(-d->windowFrameMargins[d->Left], -d->windowFrameMargins[d->Top],
604 d->windowFrameMargins[d->Right], d->windowFrameMargins[d->Bottom])
605 : rect();
606}
607
608/*!
609 Populates a style option object for this widget based on its current
610 state, and stores the output in \a option. The default implementation
611 populates \a option with the following properties.
612
613 \table
614 \header
615 \o Style Option Property
616 \o Value
617 \row
618 \o state & QStyle::State_Enabled
619 \o Corresponds to QGraphicsItem::isEnabled().
620 \row
621 \o state & QStyle::State_HasFocus
622 \o Corresponds to QGraphicsItem::hasFocus().
623 \row
624 \o state & QStyle::State_MouseOver
625 \o Corresponds to QGraphicsItem::isUnderMouse().
626 \row
627 \o direction
628 \o Corresponds to QGraphicsWidget::layoutDirection().
629 \row
630 \o rect
631 \o Corresponds to QGraphicsWidget::rect().toRect().
632 \row
633 \o palette
634 \o Corresponds to QGraphicsWidget::palette().
635 \row
636 \o fontMetrics
637 \o Corresponds to QFontMetrics(QGraphicsWidget::font()).
638 \endtable
639
640 Subclasses of QGraphicsWidget should call the base implementation, and
641 then test the type of \a option using qstyleoption_cast<>() or test
642 QStyleOption::Type before storing widget-specific options.
643
644 For example:
645
646 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicswidget.cpp 0
647
648 \sa QStyleOption::initFrom()
649*/
650void QGraphicsWidget::initStyleOption(QStyleOption *option) const
651{
652 Q_ASSERT(option);
653
654 option->state = QStyle::State_None;
655 if (isEnabled())
656 option->state |= QStyle::State_Enabled;
657 if (hasFocus())
658 option->state |= QStyle::State_HasFocus;
659 // if (window->testAttribute(Qt::WA_KeyboardFocusChange)) // ### Window
660 // option->state |= QStyle::State_KeyboardFocusChange;
661 if (isUnderMouse())
662 option->state |= QStyle::State_MouseOver;
663 if (QGraphicsWidget *w = window()) {
664 if (w->isActiveWindow())
665 option->state |= QStyle::State_Active;
666 }
667 if (isWindow())
668 option->state |= QStyle::State_Window;
669 /*
670 ###
671#ifdef Q_WS_MAC
672 extern bool qt_mac_can_clickThrough(const QGraphicsWidget *w); //qwidget_mac.cpp
673 if (!(option->state & QStyle::State_Active) && !qt_mac_can_clickThrough(widget))
674 option->state &= ~QStyle::State_Enabled;
675
676 switch (QMacStyle::widgetSizePolicy(widget)) {
677 case QMacStyle::SizeSmall:
678 option->state |= QStyle::State_Small;
679 break;
680 case QMacStyle::SizeMini:
681 option->state |= QStyle::State_Mini;
682 break;
683 default:
684 ;
685 }
686#endif
687#ifdef QT_KEYPAD_NAVIGATION
688 if (widget->hasEditFocus())
689 state |= QStyle::State_HasEditFocus;
690#endif
691 */
692 option->direction = layoutDirection();
693 option->rect = rect().toRect(); // ### truncation!
694 option->palette = palette();
695 if (!isEnabled()) {
696 option->palette.setCurrentColorGroup(QPalette::Disabled);
697 } else if (isActiveWindow()) {
698 option->palette.setCurrentColorGroup(QPalette::Active);
699 } else {
700 option->palette.setCurrentColorGroup(QPalette::Inactive);
701 }
702 option->fontMetrics = QFontMetrics(font());
703}
704
705/*!
706 \reimp
707*/
708QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
709{
710 Q_D(const QGraphicsWidget);
711 QSizeF sh;
712 if (d->layout) {
713 QSizeF marginSize(0,0);
714 if (d->margins) {
715 marginSize = QSizeF(d->margins[d->Left] + d->margins[d->Right],
716 d->margins[d->Top] + d->margins[d->Bottom]);
717 }
718 sh = d->layout->effectiveSizeHint(which, constraint - marginSize);
719 sh += marginSize;
720 } else {
721 switch (which) {
722 case Qt::MinimumSize:
723 sh = QSizeF(0, 0);
724 break;
725 case Qt::PreferredSize:
726 sh = QSizeF(50, 50); //rather arbitrary
727 break;
728 case Qt::MaximumSize:
729 sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
730 break;
731 default:
732 qWarning("QGraphicsWidget::sizeHint(): Don't know how to handle the value of 'which'");
733 break;
734 }
735 }
736 return sh;
737}
738
739/*!
740 Returns this widget's layout, or 0 if no layout is currently managing this
741 widget.
742
743 \sa setLayout()
744*/
745QGraphicsLayout *QGraphicsWidget::layout() const
746{
747 Q_D(const QGraphicsWidget);
748 return d->layout;
749}
750
751/*!
752 \fn void QGraphicsWidget::setLayout(QGraphicsLayout *layout)
753
754 Sets the layout for this widget to \a layout. Any existing layout manager
755 is deleted before the new layout is assigned. If \a layout is 0, the
756 widget is left without a layout. Existing subwidgets' geometries will
757 remain unaffected.
758
759 All widgets that are currently managed by \a layout or all of its
760 sublayouts, are automatically reparented to this item. The layout is then
761 invalidated, and the child widget geometries are adjusted according to
762 this item's geometry() and contentsMargins(). Children who are not
763 explicitly managed by \a layout remain unaffected by the layout after
764 it has been assigned to this widget.
765
766 QGraphicsWidget takes ownership of \a layout.
767
768 \sa layout(), QGraphicsLinearLayout::addItem(), QGraphicsLayout::invalidate()
769*/
770void QGraphicsWidget::setLayout(QGraphicsLayout *l)
771{
772 Q_D(QGraphicsWidget);
773 if (d->layout == l)
774 return;
775 d->setLayout_helper(l);
776 if (!l)
777 return;
778
779 // Prevent assigning a layout that is already assigned to another widget.
780 QGraphicsLayoutItem *oldParent = l->parentLayoutItem();
781 if (oldParent && oldParent != this) {
782 qWarning("QGraphicsWidget::setLayout: Attempting to set a layout on %s"
783 " \"%s\", when the layout already has a parent",
784 metaObject()->className(), qPrintable(objectName()));
785 return;
786 }
787
788 // Install and activate the layout.
789 l->setParentLayoutItem(this);
790 l->d_func()->reparentChildItems(this);
791 l->invalidate();
792}
793
794/*!
795 Adjusts the size of the widget to its effective preferred size hint.
796
797 This function is called implicitly when the item is shown for the first
798 time.
799
800 \sa effectiveSizeHint(), Qt::MinimumSize
801*/
802void QGraphicsWidget::adjustSize()
803{
804 QSizeF sz = effectiveSizeHint(Qt::PreferredSize);
805 // What if sz is not valid?!
806 if (sz.isValid())
807 resize(sz);
808}
809
810/*!
811 \property QGraphicsWidget::layoutDirection
812 \brief the layout direction for this widget.
813
814 This property modifies this widget's and all of its descendants'
815 Qt::WA_RightToLeft attribute. It also sets this widget's
816 Qt::WA_SetLayoutDirection attribute.
817
818 The widget's layout direction determines the order in which the layout
819 manager horizontally arranges subwidgets of this widget. The default
820 value depends on the language and locale of the application, and is
821 typically in the same direction as words are read and written. With
822 Qt::LeftToRight, the layout starts placing subwidgets from the left
823 side of this widget towards the right. Qt::RightToLeft does the opposite -
824 the layout will place widgets starting from the right edge moving towards
825 the left.
826
827 Subwidgets inherit their layout direction from the parent. Top-level
828 widget items inherit their layout direction from
829 QGraphicsScene::layoutDirection. If you change a widget's layout direction
830 by calling setLayoutDirection(), the widget will send itself a
831 \l{QEvent::LayoutDirectionChange}{LayoutDirectionChange} event, and then
832 propagate the new layout direction to all its descendants.
833
834 \sa QWidget::layoutDirection, QApplication::layoutDirection
835*/
836Qt::LayoutDirection QGraphicsWidget::layoutDirection() const
837{
838 return testAttribute(Qt::WA_RightToLeft) ? Qt::RightToLeft : Qt::LeftToRight;
839}
840void QGraphicsWidget::setLayoutDirection(Qt::LayoutDirection direction)
841{
842 Q_D(QGraphicsWidget);
843 setAttribute(Qt::WA_SetLayoutDirection, true);
844 d->setLayoutDirection_helper(direction);
845}
846void QGraphicsWidget::unsetLayoutDirection()
847{
848 Q_D(QGraphicsWidget);
849 setAttribute(Qt::WA_SetLayoutDirection, false);
850 d->resolveLayoutDirection();
851}
852
853/*!
854 Returns a pointer to the widget's style. If this widget does not have any
855 explicitly assigned style, the scene's style is returned instead. In turn,
856 if the scene does not have any assigned style, this function returns
857 QApplication::style().
858
859 \sa setStyle()
860*/
861QStyle *QGraphicsWidget::style() const
862{
863 if (QStyle *style = widgetStyles()->styleForWidget(this))
864 return style;
865 // ### This is not thread-safe. QApplication::style() is not thread-safe.
866 return scene() ? scene()->style() : QApplication::style();
867}
868
869/*!
870 Sets the widget's style to \a style. QGraphicsWidget does \e not take
871 ownership of \a style.
872
873 If no style is assigned, or \a style is 0, the widget will use
874 QGraphicsScene::style() (if this has been set). Otherwise the widget will
875 use QApplication::style().
876
877 This function sets the Qt::WA_SetStyle attribute if \a style is not 0;
878 otherwise it clears the attribute.
879
880 \sa style()
881*/
882void QGraphicsWidget::setStyle(QStyle *style)
883{
884 setAttribute(Qt::WA_SetStyle, style != 0);
885 widgetStyles()->setStyleForWidget(this, style);
886
887 // Deliver StyleChange to the widget itself (doesn't propagate).
888 QEvent event(QEvent::StyleChange);
889 QApplication::sendEvent(this, &event);
890}
891
892/*!
893 \property QGraphicsWidget::font
894 \brief the widgets' font
895
896 This property provides the widget's font.
897
898 QFont consists of font properties that have been explicitly defined and
899 properties implicitly inherited from the widget's parent. Hence, font()
900 can return a different font compared to the one set with setFont().
901 This scheme allows you to define single entries in a font without
902 affecting the font's inherited entries.
903
904 When a widget's font changes, it resolves its entries against its
905 parent widget. If the widget does not have a parent widget, it resolves
906 its entries against the scene. The widget then sends itself a
907 \l{QEvent::FontChange}{FontChange} event and notifies all its
908 descendants so that they can resolve their fonts as well.
909
910 By default, this property contains the application's default font.
911
912 \sa QApplication::font(), QGraphicsScene::font, QFont::resolve()
913*/
914QFont QGraphicsWidget::font() const
915{
916 Q_D(const QGraphicsWidget);
917 return d->font;
918}
919void QGraphicsWidget::setFont(const QFont &font)
920{
921 Q_D(QGraphicsWidget);
922 setAttribute(Qt::WA_SetFont, font.resolve() != 0);
923
924 QFont naturalFont = d->naturalWidgetFont();
925 QFont resolvedFont = font.resolve(naturalFont);
926 d->setFont_helper(resolvedFont);
927}
928
929/*!
930 \property QGraphicsWidget::palette
931 \brief the widget's palette
932
933 This property provides the widget's palette. The palette provides colors
934 and brushes for color groups (e.g., QPalette::Button) and states (e.g.,
935 QPalette::Inactive), loosely defining the general look of the widget and
936 its children.
937
938 QPalette consists of color groups that have been explicitly defined, and
939 groups that are implicitly inherited from the widget's parent. Because of
940 this, palette() can return a different palette than what has been set with
941 setPalette(). This scheme allows you to define single entries in a palette
942 without affecting the palette's inherited entries.
943
944 When a widget's palette changes, it resolves its entries against its
945 parent widget, or if it doesn't have a parent widget, it resolves against
946 the scene. It then sends itself a \l{QEvent::PaletteChange}{PaletteChange}
947 event, and notifies all its descendants so they can resolve their palettes
948 as well.
949
950 By default, this property contains the application's default palette.
951
952 \sa QApplication::palette(), QGraphicsScene::palette, QPalette::resolve()
953*/
954QPalette QGraphicsWidget::palette() const
955{
956 Q_D(const QGraphicsWidget);
957 return d->palette;
958}
959void QGraphicsWidget::setPalette(const QPalette &palette)
960{
961 Q_D(QGraphicsWidget);
962 setAttribute(Qt::WA_SetPalette, palette.resolve() != 0);
963
964 QPalette naturalPalette = d->naturalWidgetPalette();
965 QPalette resolvedPalette = palette.resolve(naturalPalette);
966 d->setPalette_helper(resolvedPalette);
967}
968
969/*!
970 If this widget is currently managed by a layout, this function notifies
971 the layout that the widget's size hints have changed and the layout
972 may need to resize and reposition the widget accordingly.
973
974 Call this function if the widget's sizeHint() has changed.
975
976 \sa QGraphicsLayout::invalidate()
977*/
978void QGraphicsWidget::updateGeometry()
979{
980 QGraphicsLayoutItem::updateGeometry();
981 QGraphicsLayoutItem *parentItem = parentLayoutItem();
982
983 if (parentItem && parentItem->isLayout()) {
984 parentItem->updateGeometry();
985 } else {
986 if (parentItem) {
987 QGraphicsWidget *parentWid = parentWidget(); //###
988 if (parentWid->isVisible())
989 QApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest));
990 }
991 bool wasResized = testAttribute(Qt::WA_Resized);
992 resize(size()); // this will restrict the size
993 setAttribute(Qt::WA_Resized, wasResized);
994 }
995}
996
997/*!
998 \reimp
999
1000 QGraphicsWidget uses the base implementation of this function to catch and
1001 deliver events related to state changes in the item. Because of this, it is
1002 very important that subclasses call the base implementation.
1003
1004 \a change specifies the type of change, and \a value is the new value.
1005
1006 For example, QGraphicsWidget uses ItemVisibleChange to deliver
1007 \l{QEvent::Show} {Show} and \l{QEvent::Hide}{Hide} events,
1008 ItemPositionHasChanged to deliver \l{QEvent::Move}{Move} events,
1009 and ItemParentChange both to deliver \l{QEvent::ParentChange}
1010 {ParentChange} events, and for managing the focus chain.
1011
1012 QGraphicsWidget enables the ItemSendsGeometryChanges flag by default in
1013 order to track position changes.
1014
1015 \sa QGraphicsItem::itemChange()
1016*/
1017QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
1018{
1019 Q_D(QGraphicsWidget);
1020 switch (change) {
1021 case ItemEnabledHasChanged: {
1022 // Send EnabledChange after the enabled state has changed.
1023 QEvent event(QEvent::EnabledChange);
1024 QApplication::sendEvent(this, &event);
1025 break;
1026 }
1027 case ItemVisibleChange:
1028 if (value.toBool()) {
1029 // Send Show event before the item has been shown.
1030 QShowEvent event;
1031 QApplication::sendEvent(this, &event);
1032 bool resized = testAttribute(Qt::WA_Resized);
1033 if (!resized) {
1034 adjustSize();
1035 setAttribute(Qt::WA_Resized, false);
1036 }
1037 }
1038 break;
1039 case ItemVisibleHasChanged:
1040 if (!value.toBool()) {
1041 // Send Hide event after the item has been hidden.
1042 QHideEvent event;
1043 QApplication::sendEvent(this, &event);
1044 }
1045 break;
1046 case ItemPositionHasChanged:
1047 d->setGeometryFromSetPos();
1048 break;
1049 case ItemParentChange: {
1050 QGraphicsItem *parent = qVariantValue<QGraphicsItem *>(value);
1051 d->fixFocusChainBeforeReparenting((parent && parent->isWidget()) ? static_cast<QGraphicsWidget *>(parent) : 0, scene());
1052
1053 // Deliver ParentAboutToChange.
1054 QEvent event(QEvent::ParentAboutToChange);
1055 QApplication::sendEvent(this, &event);
1056 break;
1057 }
1058 case ItemParentHasChanged: {
1059 // Deliver ParentChange.
1060 QEvent event(QEvent::ParentChange);
1061 QApplication::sendEvent(this, &event);
1062 break;
1063 }
1064 case ItemCursorHasChanged: {
1065 // Deliver CursorChange.
1066 QEvent event(QEvent::CursorChange);
1067 QApplication::sendEvent(this, &event);
1068 break;
1069 }
1070 case ItemToolTipHasChanged: {
1071 // Deliver ToolTipChange.
1072 QEvent event(QEvent::ToolTipChange);
1073 QApplication::sendEvent(this, &event);
1074 break;
1075 }
1076 default:
1077 break;
1078 }
1079 return QGraphicsItem::itemChange(change, value);
1080}
1081
1082/*!
1083 \internal
1084
1085 This virtual function is used to notify changes to any property (both
1086 dynamic properties, and registered with Q_PROPERTY) in the
1087 widget. Depending on the property itself, the notification can be
1088 delivered before or after the value has changed.
1089
1090 \a propertyName is the name of the property (e.g., "size" or "font"), and
1091 \a value is the (proposed) new value of the property. The function returns
1092 the new value, which may be different from \a value if the notification
1093 supports adjusting the property value. The base implementation simply
1094 returns \a value for any \a propertyName.
1095
1096 QGraphicsWidget delivers notifications for the following properties:
1097
1098 \table \o propertyName \o Property
1099 \row \o layoutDirection \o QGraphicsWidget::layoutDirection
1100 \row \o size \o QGraphicsWidget::size
1101 \row \o font \o QGraphicsWidget::font
1102 \row \o palette \o QGraphicsWidget::palette
1103 \endtable
1104
1105 \sa itemChange()
1106*/
1107QVariant QGraphicsWidget::propertyChange(const QString &propertyName, const QVariant &value)
1108{
1109 Q_UNUSED(propertyName);
1110 return value;
1111}
1112
1113/*!
1114 QGraphicsWidget's implementation of sceneEvent() simply passes \a event to
1115 QGraphicsWidget::event(). You can handle all events for your widget in
1116 event() or in any of the convenience functions; you should not have to
1117 reimplement this function in a subclass of QGraphicsWidget.
1118
1119 \sa QGraphicsItem::sceneEvent()
1120*/
1121bool QGraphicsWidget::sceneEvent(QEvent *event)
1122{
1123 return QGraphicsItem::sceneEvent(event);
1124}
1125
1126/*!
1127 This event handler, for \a event, receives events for the window frame if
1128 this widget is a window. Its base implementation provides support for
1129 default window frame interaction such as moving, resizing, etc.
1130
1131 You can reimplement this handler in a subclass of QGraphicsWidget to
1132 provide your own custom window frame interaction support.
1133
1134 Returns true if \a event has been recognized and processed; otherwise,
1135 returns false.
1136
1137 \sa event()
1138*/
1139bool QGraphicsWidget::windowFrameEvent(QEvent *event)
1140{
1141 Q_D(QGraphicsWidget);
1142 switch (event->type()) {
1143 case QEvent::GraphicsSceneMousePress:
1144 d->windowFrameMousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
1145 break;
1146 case QEvent::GraphicsSceneMouseMove:
1147 d->ensureWindowData();
1148 if (d->windowData->grabbedSection != Qt::NoSection) {
1149 d->windowFrameMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
1150 event->accept();
1151 }
1152 break;
1153 case QEvent::GraphicsSceneMouseRelease:
1154 d->windowFrameMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
1155 break;
1156 case QEvent::GraphicsSceneHoverMove:
1157 d->windowFrameHoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
1158 break;
1159 case QEvent::GraphicsSceneHoverLeave:
1160 d->windowFrameHoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
1161 break;
1162 default:
1163 break;
1164 }
1165 return event->isAccepted();
1166}
1167
1168/*!
1169 \since 4.4
1170
1171 Returns the window frame section at position \a pos, or
1172 Qt::NoSection if there is no window frame section at this
1173 position.
1174
1175 This function is used in QGraphicsWidget's base implementation for window
1176 frame interaction.
1177
1178 You can reimplement this function if you want to customize how a window
1179 can be interactively moved or resized. For instance, if you only want to
1180 allow a window to be resized by the bottom right corner, you can
1181 reimplement this function to return Qt::NoSection for all sections except
1182 Qt::BottomRightSection.
1183
1184 \sa windowFrameEvent(), paintWindowFrame(), windowFrameGeometry()
1185*/
1186Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) const
1187{
1188 Q_D(const QGraphicsWidget);
1189
1190 const QRectF r = windowFrameRect();
1191 if (!r.contains(pos))
1192 return Qt::NoSection;
1193
1194 const qreal left = r.left();
1195 const qreal top = r.top();
1196 const qreal right = r.right();
1197 const qreal bottom = r.bottom();
1198 const qreal x = pos.x();
1199 const qreal y = pos.y();
1200
1201 const qreal cornerMargin = 20;
1202 //### Not sure of this one, it should be the same value for all edges.
1203 const qreal windowFrameWidth = d->windowFrameMargins
1204 ? d->windowFrameMargins[d->Left] : 0;
1205
1206 Qt::WindowFrameSection s = Qt::NoSection;
1207 if (x <= left + cornerMargin) {
1208 if (y <= top + windowFrameWidth || (x <= left + windowFrameWidth && y <= top + cornerMargin)) {
1209 s = Qt::TopLeftSection;
1210 } else if (y >= bottom - windowFrameWidth || (x <= left + windowFrameWidth && y >= bottom - windowFrameWidth)) {
1211 s = Qt::BottomLeftSection;
1212 } else if (x <= left + windowFrameWidth) {
1213 s = Qt::LeftSection;
1214 }
1215 } else if (x >= right - cornerMargin) {
1216 if (y <= top + windowFrameWidth || (x >= right - windowFrameWidth && y <= top + cornerMargin)) {
1217 s = Qt::TopRightSection;
1218 } else if (y >= bottom - windowFrameWidth || (x >= right - windowFrameWidth && y >= bottom - windowFrameWidth)) {
1219 s = Qt::BottomRightSection;
1220 } else if (x >= right - windowFrameWidth) {
1221 s = Qt::RightSection;
1222 }
1223 } else if (y <= top + windowFrameWidth) {
1224 s = Qt::TopSection;
1225 } else if (y >= bottom - windowFrameWidth) {
1226 s = Qt::BottomSection;
1227 }
1228 if (s == Qt::NoSection) {
1229 QRectF r1 = r;
1230 r1.setHeight(d->windowFrameMargins
1231 ? d->windowFrameMargins[d->Top] : 0);
1232 if (r1.contains(pos))
1233 s = Qt::TitleBarArea;
1234 }
1235 return s;
1236}
1237
1238/*!
1239 \reimp
1240
1241 Handles the \a event. QGraphicsWidget handles the following
1242 events:
1243
1244 \table \o Event \o Usage
1245 \row \o Polish
1246 \o Delivered to the widget some time after it has been
1247 shown.
1248 \row \o GraphicsSceneMove
1249 \o Delivered to the widget after its local position has
1250 changed.
1251 \row \o GraphicsSceneResize
1252 \o Delivered to the widget after its size has changed.
1253 \row \o Show
1254 \o Delivered to the widget before it has been shown.
1255 \row \o Hide
1256 \o Delivered to the widget after it has been hidden.
1257 \row \o PaletteChange
1258 \o Delivered to the widget after its palette has changed.
1259 \row \o FontChange
1260 \o Delivered to the widget after its font has changed.
1261 \row \o EnabledChange