source: trunk/src/gui/widgets/qfocusframe.cpp@ 966

Last change on this file since 966 was 846, checked in by Dmitry A. Kuminov, 14 years ago

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

File size: 10.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 "qfocusframe.h"
43#include "qstyle.h"
44#include "qbitmap.h"
45#include "qstylepainter.h"
46#include "qstyleoption.h"
47#include "qdebug.h"
48#include <private/qwidget_p.h>
49
50QT_BEGIN_NAMESPACE
51
52class QFocusFramePrivate : public QWidgetPrivate
53{
54 Q_DECLARE_PUBLIC(QFocusFrame)
55 QWidget *widget;
56 QWidget *frameParent;
57 bool showFrameAboveWidget;
58public:
59 QFocusFramePrivate() {
60 widget = 0;
61 frameParent = 0;
62 sendChildEvents = false;
63 showFrameAboveWidget = false;
64 }
65 void updateSize();
66 void update();
67};
68
69void QFocusFramePrivate::update()
70{
71 Q_Q(QFocusFrame);
72 q->setParent(frameParent);
73 updateSize();
74 if (q->parentWidget()->rect().intersects(q->geometry())) {
75 if (showFrameAboveWidget)
76 q->raise();
77 else
78 q->stackUnder(widget);
79 q->show();
80 } else {
81 q->hide();
82 }
83}
84
85void QFocusFramePrivate::updateSize()
86{
87 Q_Q(QFocusFrame);
88 int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin),
89 hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
90 QPoint pos(widget->x(), widget->y());
91 if (q->parentWidget() != widget->parentWidget())
92 pos = widget->parentWidget()->mapTo(q->parentWidget(), pos);
93 QRect geom(pos.x()-hmargin, pos.y()-vmargin,
94 widget->width()+(hmargin*2), widget->height()+(vmargin*2));
95 if(q->geometry() == geom)
96 return;
97
98 q->setGeometry(geom);
99 QStyleHintReturnMask mask;
100 QStyleOption opt;
101 q->initStyleOption(&opt);
102 if (q->style()->styleHint(QStyle::SH_FocusFrame_Mask, &opt, q, &mask))
103 q->setMask(mask.region);
104}
105
106/*!
107 Initialize \a option with the values from this QFocusFrame. This method is useful
108 for subclasses when they need a QStyleOption, but don't want to fill
109 in all the information themselves.
110
111 \sa QStyleOption::initFrom()
112*/
113void QFocusFrame::initStyleOption(QStyleOption *option) const
114{
115 if (!option)
116 return;
117
118 option->initFrom(this);
119}
120
121/*!
122 \class QFocusFrame
123 \brief The QFocusFrame widget provides a focus frame which can be
124 outside of a widget's normal paintable area.
125
126 \ingroup basicwidgets
127
128
129 Normally an application will not need to create its own
130 QFocusFrame as QStyle will handle this detail for
131 you. A style writer can optionally use a QFocusFrame to have a
132 focus area outside of the widget's paintable geometry. In this way
133 space need not be reserved for the widget to have focus but only
134 set on a QWidget with QFocusFrame::setWidget. It is, however,
135 legal to create your own QFocusFrame on a custom widget and set
136 its geometry manually via QWidget::setGeometry however you will
137 not get auto-placement when the focused widget changes size or
138 placement.
139*/
140
141/*!
142 Constructs a QFocusFrame.
143
144 The focus frame will not monitor \a parent for updates but rather
145 can be placed manually or by using QFocusFrame::setWidget. A
146 QFocusFrame sets Qt::WA_NoChildEventsForParent attribute; as a
147 result the parent will not receive a QEvent::ChildInserted event,
148 this will make it possible to manually set the geometry of the
149 QFocusFrame inside of a QSplitter or other child event monitoring
150 widget.
151
152 \sa QFocusFrame::setWidget()
153*/
154
155QFocusFrame::QFocusFrame(QWidget *parent)
156 : QWidget(*new QFocusFramePrivate, parent, 0)
157{
158 setAttribute(Qt::WA_TransparentForMouseEvents);
159 setFocusPolicy(Qt::NoFocus);
160 setAttribute(Qt::WA_NoChildEventsForParent, true);
161 setAttribute(Qt::WA_AcceptDrops, style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this));
162}
163
164/*!
165 Destructor.
166*/
167
168QFocusFrame::~QFocusFrame()
169{
170}
171
172/*!
173 QFocusFrame will track changes to \a widget and resize itself automatically.
174 If the monitored widget's parent changes, QFocusFrame will follow the widget
175 and place itself around the widget automatically. If the monitored widget is deleted,
176 QFocusFrame will set it to zero.
177
178 \sa QFocusFrame::widget()
179*/
180
181void
182QFocusFrame::setWidget(QWidget *widget)
183{
184 Q_D(QFocusFrame);
185
186 if (style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this))
187 d->showFrameAboveWidget = true;
188 else
189 d->showFrameAboveWidget = false;
190
191 if (widget == d->widget)
192 return;
193 if (d->widget) {
194 // Remove event filters from the widget hierarchy.
195 QWidget *p = d->widget;
196 do {
197 p->removeEventFilter(this);
198 if (!d->showFrameAboveWidget || p == d->frameParent)
199 break;
200 p = p->parentWidget();
201 }while (p);
202 }
203 if (widget && !widget->isWindow() && widget->parentWidget()->windowType() != Qt::SubWindow) {
204 d->widget = widget;
205 d->widget->installEventFilter(this);
206 QWidget *p = widget->parentWidget();
207 QWidget *prev = 0;
208 if (d->showFrameAboveWidget) {
209 // Find the right parent for the focus frame.
210 while (p) {
211 // Traverse the hirerarchy of the 'widget' for setting event filter.
212 // During this if come across toolbar or a top level, use that
213 // as the parent for the focus frame. If we find a scroll area
214 // use its viewport as the parent.
215 bool isScrollArea = false;
216 if (p->isWindow() || p->inherits("QToolBar") || (isScrollArea = p->inherits("QAbstractScrollArea"))) {
217 d->frameParent = p;
218 // The previous one in the hierarchy will be the viewport.
219 if (prev && isScrollArea)
220 d->frameParent = prev;
221 break;
222 } else {
223 p->installEventFilter(this);
224 prev = p;
225 p = p->parentWidget();
226 }
227 }
228 } else {
229 d->frameParent = p;
230 }
231 d->update();
232 } else {
233 d->widget = 0;
234 hide();
235 }
236}
237
238/*!
239 Returns the currently monitored widget for automatically resize and
240 update.
241
242 \sa QFocusFrame::setWidget()
243*/
244
245QWidget *
246QFocusFrame::widget() const
247{
248 Q_D(const QFocusFrame);
249 return d->widget;
250}
251
252
253/*! \reimp */
254void
255QFocusFrame::paintEvent(QPaintEvent *)
256{
257 Q_D(QFocusFrame);
258 QStylePainter p(this);
259 QStyleOption option;
260 initStyleOption(&option);
261 int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin);
262 int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
263 QWidgetPrivate *wd = qt_widget_private(d->widget);
264 QRect rect = wd->clipRect().adjusted(0, 0, hmargin*2, vmargin*2);
265 p.setClipRect(rect);
266 p.drawControl(QStyle::CE_FocusFrame, option);
267}
268
269
270/*! \reimp */
271bool
272QFocusFrame::eventFilter(QObject *o, QEvent *e)
273{
274 Q_D(QFocusFrame);
275 if(o == d->widget) {
276 switch(e->type()) {
277 case QEvent::Move:
278 case QEvent::Resize:
279 d->updateSize();
280 break;
281 case QEvent::Hide:
282 case QEvent::StyleChange:
283 hide();
284 break;
285 case QEvent::ParentChange:
286 if (d->showFrameAboveWidget) {
287 QWidget *w = d->widget;
288 setWidget(0);
289 setWidget(w);
290 } else {
291 d->update();
292 }
293 break;
294 case QEvent::Show:
295 d->update();
296 show();
297 break;
298 case QEvent::PaletteChange:
299 setPalette(d->widget->palette());
300 break;
301 case QEvent::ZOrderChange:
302 if (style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this))
303 raise();
304 else
305 stackUnder(d->widget);
306 break;
307 case QEvent::Destroy:
308 setWidget(0);
309 break;
310 default:
311 break;
312 }
313 } else if (d->showFrameAboveWidget) {
314 // Handle changes in the parent widgets we are monitoring.
315 switch(e->type()) {
316 case QEvent::Move:
317 case QEvent::Resize:
318 d->updateSize();
319 break;
320 case QEvent::ZOrderChange:
321 raise();
322 break;
323 default:
324 break;
325 }
326 }
327 return false;
328}
329
330/*! \reimp */
331bool QFocusFrame::event(QEvent *e)
332{
333 return QWidget::event(e);
334}
335
336QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.