|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (developer.feedback@nokia.com) |
|
6 ** |
|
7 ** This file is part of the HbCore module of the UI Extensions for Mobile. |
|
8 ** |
|
9 ** GNU Lesser General Public License Usage |
|
10 ** This file may be used under the terms of the GNU Lesser General Public |
|
11 ** License version 2.1 as published by the Free Software Foundation and |
|
12 ** appearing in the file LICENSE.LGPL included in the packaging of this file. |
|
13 ** Please review the following information to ensure the GNU Lesser General |
|
14 ** Public License version 2.1 requirements will be met: |
|
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
16 ** |
|
17 ** In addition, as a special exception, Nokia gives you certain additional |
|
18 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
20 ** |
|
21 ** If you have questions regarding the use of this file, please contact |
|
22 ** Nokia at developer.feedback@nokia.com. |
|
23 ** |
|
24 ****************************************************************************/ |
|
25 |
|
26 #include "hbpopup.h" |
|
27 #include "hbpopup_p.h" |
|
28 #include "hbinstance.h" |
|
29 #include "hbpopupmanager_p.h" |
|
30 #include "hbdeviceprofile.h" |
|
31 #include "hbevent.h" |
|
32 #include "hbgraphicsscene.h" |
|
33 #include "hbgraphicsscene_p.h" |
|
34 #include "hbtooltip.h" |
|
35 #include <QTimer> |
|
36 #include <QGraphicsSceneMouseEvent> |
|
37 #include <QShowEvent> |
|
38 #include <QHideEvent> |
|
39 #include <QEventLoop> |
|
40 #include <QPointer> |
|
41 #include <QApplication> // krazy:exclude=qclasses |
|
42 |
|
43 #include <hbwidgetfeedback.h> |
|
44 |
|
45 #ifdef HB_EFFECTS |
|
46 #include "hbeffectinternal_p.h" |
|
47 bool HbPopupPrivate::popupEffectsLoaded = false; |
|
48 #endif |
|
49 /*! |
|
50 @stable |
|
51 @hbcore |
|
52 \class HbPopup |
|
53 \brief HbPopup is a base class for different popup notes in Hb library. |
|
54 |
|
55 \image html hbpopup.png A popup with a header widget, a list as a content widget, and two |
|
56 action buttons. |
|
57 |
|
58 HbPopup is a concrete class. The content for a custom popup is implemented in |
|
59 a separate widget, which is set to the popup with method setContentWidget(). |
|
60 |
|
61 Lastly shown popup is always positioned in Z order on the the top of already visible popups. |
|
62 A popup can be permanent or automatically dismissed after a time-out. |
|
63 Modal popups interrupt any other user interaction outside of the popup while they are visible, |
|
64 whereas non-modal popups do not. |
|
65 |
|
66 An example of how to create a simple modal popup and show it. |
|
67 \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,13} |
|
68 |
|
69 An example of how to create a non-modal popup and show it. |
|
70 \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,26} |
|
71 |
|
72 */ |
|
73 |
|
74 /*! |
|
75 \reimp |
|
76 \fn int HbPopup::type() const |
|
77 */ |
|
78 |
|
79 /*! |
|
80 \enum HbPopup::DefaultTimeout |
|
81 |
|
82 This enum defines available default timeout values to be used in method |
|
83 setTimeout(HbPopup::DefaultTimeout). |
|
84 */ |
|
85 |
|
86 /*! |
|
87 \var HbPopup::NoTimeout |
|
88 |
|
89 No timeout is defined for automatically closing the popup. i.e. the popup is permanent. |
|
90 */ |
|
91 |
|
92 /*! |
|
93 \var HbPopup::ConfirmationNoteTimeout |
|
94 |
|
95 Timeout value intended to be used by confirmation notes. |
|
96 */ |
|
97 |
|
98 /*! |
|
99 \var HbPopup::StandardTimeout |
|
100 |
|
101 The default timeout value intended to be used by most non-permanent popups e.g. by notes. |
|
102 */ |
|
103 |
|
104 /*! |
|
105 \var HbPopup::ContextMenuTimeout |
|
106 |
|
107 The default timeout value intended to be used by context menus. |
|
108 */ |
|
109 |
|
110 /*! |
|
111 \enum HbPopup::DismissPolicy |
|
112 |
|
113 This enum defines available dismiss policy values. |
|
114 |
|
115 The dismiss policy defines what user actions will cause the popup to be dismissed i.e. closed. |
|
116 */ |
|
117 |
|
118 /*! |
|
119 \var HbPopup::NoDismiss |
|
120 |
|
121 The popup cannot be dismissed automatically by user interaction. |
|
122 */ |
|
123 |
|
124 /*! |
|
125 \var HbPopup::TapInside |
|
126 |
|
127 The popup is dismissed when user taps within the bounding rectangle of the popup. |
|
128 */ |
|
129 |
|
130 /*! |
|
131 \var HbPopup::TapOutside |
|
132 |
|
133 The popup is dismissed when user taps outside of the bounding rectangle of the popup. |
|
134 */ |
|
135 |
|
136 /*! |
|
137 \var HbPopup::TapAnywhere |
|
138 |
|
139 The popup is dismissed when user taps either within or outside |
|
140 of the bounding rectangle of the popup. |
|
141 */ |
|
142 |
|
143 /*! |
|
144 \enum HbPopup::FrameType |
|
145 |
|
146 This enum defines available frame type values. |
|
147 |
|
148 The frame types defines what frame item backgrounds will be used by the popup. |
|
149 */ |
|
150 |
|
151 /*! |
|
152 \var HbPopup::Strong |
|
153 |
|
154 The popup is using strong frame. |
|
155 */ |
|
156 |
|
157 /*! |
|
158 \var HbPopup::Weak |
|
159 |
|
160 The popup is using weak frame. |
|
161 */ |
|
162 |
|
163 /*! |
|
164 \fn void HbPopup::aboutToShow(); |
|
165 |
|
166 This signal is emitted when the popup is about to be shown i.e. when method show() is called. |
|
167 */ |
|
168 |
|
169 /*! |
|
170 \fn void HbPopup::aboutToHide(); |
|
171 |
|
172 This signal is emitted when the popup is about to be hidden i.e. when method hide() is called. |
|
173 */ |
|
174 |
|
175 |
|
176 /*! |
|
177 \fn void HbPopup::aboutToClose(); |
|
178 |
|
179 This signal is emitted when the popup is about to be closed i.e. when method close() is called |
|
180 or the popup is |
|
181 dismissed by the user or timeout. |
|
182 */ |
|
183 |
|
184 static const struct { HbPopup::DefaultTimeout timeout; int value; } timeoutValues[] = |
|
185 { |
|
186 {HbPopup::NoTimeout,0}, |
|
187 {HbPopup::ConfirmationNoteTimeout,1500}, |
|
188 {HbPopup::StandardTimeout,3000}, |
|
189 {HbPopup::ContextMenuTimeout,6000}, |
|
190 }; |
|
191 |
|
192 HbPopupBackGround::HbPopupBackGround(HbPopup * popup, QGraphicsItem *parent) : |
|
193 QGraphicsItem(parent), |
|
194 popup(popup) |
|
195 { |
|
196 // This is needed to be able to block moving the focus to items behind background item by |
|
197 // clicking on them. |
|
198 setFlag(QGraphicsItem::ItemIsFocusable); |
|
199 |
|
200 #if QT_VERSION >= 0x040600 |
|
201 setFlag(QGraphicsItem::ItemHasNoContents, true); |
|
202 #endif |
|
203 } |
|
204 |
|
205 HbPopupBackGround::~HbPopupBackGround() |
|
206 { |
|
207 // Set backgroundItem to 0 to avoid double deletion |
|
208 // e.g. when backgroundItem is deleted by scene before its popup |
|
209 if (popup) { |
|
210 HbPopupPrivate::d_ptr(popup)->backgroundItem = 0; |
|
211 } |
|
212 } |
|
213 |
|
214 void HbPopupBackGround::setRect(QRectF rect) |
|
215 { |
|
216 mRect = rect; |
|
217 } |
|
218 |
|
219 QRectF HbPopupBackGround::boundingRect() const |
|
220 { |
|
221 if(!mRect.isValid()){ |
|
222 // set backgroundItem's size so that it is big enough |
|
223 // to cover the screen both landscape and portrait mode |
|
224 const QSizeF screenSize = HbDeviceProfile::profile(this).logicalSize(); |
|
225 qreal dim = qMax(screenSize.width(), screenSize.height()); |
|
226 mRect.adjust(0,0,dim,dim); |
|
227 } |
|
228 return mRect; |
|
229 } |
|
230 |
|
231 void HbPopupBackGround::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ) |
|
232 { |
|
233 Q_UNUSED(option) |
|
234 Q_UNUSED(widget); |
|
235 Q_UNUSED(painter); |
|
236 } |
|
237 |
|
238 bool HbPopupBackGround::sceneEvent(QEvent *event) |
|
239 { |
|
240 if (event->type() == QEvent::GraphicsSceneMousePress) { |
|
241 HbPopupPrivate::d_ptr(popup)->handleBackgroundMousePressEvent(); |
|
242 } |
|
243 if (event->type() == QEvent::GraphicsSceneMouseRelease) { |
|
244 HbPopupPrivate::d_ptr(popup)->handleBackgroundMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event)); |
|
245 } |
|
246 if (event->type() == QEvent::FocusIn && scene()) { |
|
247 // Prevents last focus item losing its focus |
|
248 // This event is received only when popup is modal |
|
249 QFocusEvent restoreLastFocus(QEvent::FocusIn,Qt::OtherFocusReason); |
|
250 QApplication::sendEvent(scene(),&restoreLastFocus); // krazy:exclude=qclasses |
|
251 } |
|
252 // accept events only for modal popups |
|
253 if(popup->isModal()){ |
|
254 event->accept(); |
|
255 return true; |
|
256 } else { |
|
257 event->ignore(); |
|
258 } |
|
259 return QGraphicsItem::sceneEvent(event); |
|
260 } |
|
261 |
|
262 HbPopupPrivate::HbPopupPrivate( ) : |
|
263 eventLoop(0), |
|
264 hasEffects(false), |
|
265 closed(false), |
|
266 hidingInProgress(true), |
|
267 delayedHide(false), |
|
268 deleteOnClose(false), |
|
269 modal(true), // must be in sync QGraphicsItem::ItemIsFocusable of backgroundItem |
|
270 fadeBackground(true), |
|
271 inDestruction(false), |
|
272 aboutToShowSignalGuard(false), |
|
273 duplicateShowEvent(false), |
|
274 timedOut(false), |
|
275 timeout(HbPopupPrivate::timeoutValue(HbPopup::StandardTimeout)), |
|
276 // priorityValue(HbPopup::Default), |
|
277 priorityValue(0), |
|
278 dismissPolicy(HbPopup::TapOutside), |
|
279 backgroundItem(0), |
|
280 mousePressLocation(None), |
|
281 frameType(HbPopup::Strong), |
|
282 preferredPosSet(false), |
|
283 mStartEffect(false), |
|
284 timeoutTimerInstance(0) |
|
285 { |
|
286 } |
|
287 |
|
288 HbPopupPrivate::~HbPopupPrivate() |
|
289 { |
|
290 } |
|
291 |
|
292 void HbPopupPrivate::init() |
|
293 { |
|
294 Q_Q(HbPopup); |
|
295 |
|
296 q->setAttribute(Hb::InsidePopup); |
|
297 |
|
298 // By default popups are focusable |
|
299 q->setFocusPolicy(Qt::StrongFocus); |
|
300 q->setBackgroundItem(HbStyle::P_Popup_background); |
|
301 |
|
302 // Only for popup without parent |
|
303 if (!q->parentItem()) { |
|
304 backgroundItem = new HbPopupBackGround(q); |
|
305 backgroundItem->setVisible(false); |
|
306 |
|
307 // Popup is invisible by default (explicit show or exec call is required) |
|
308 q->setVisible(false); |
|
309 } |
|
310 hidingInProgress = false; |
|
311 } |
|
312 |
|
313 /* |
|
314 * *********** Begin of private features *********** |
|
315 */ |
|
316 |
|
317 /* |
|
318 * Sets the priority for a popup. |
|
319 * A popup with higher priority is always shown on top of a popup with lower priority. |
|
320 * In case of popups with same priority the lastly shown will be on top. |
|
321 * Default priority is HbPopup::Default |
|
322 * \sa priority() |
|
323 */ |
|
324 void HbPopupPrivate::setPriority(quint8 priority) |
|
325 { |
|
326 //TODO: consider implementing dynamic change of prorities |
|
327 // i.e. if the priority changes while the popup is registered to popupManager |
|
328 // then re-register it to get its Z value updated |
|
329 priorityValue=priority; |
|
330 } |
|
331 |
|
332 /* |
|
333 * *********** End of private features *********** |
|
334 */ |
|
335 #ifdef HB_EFFECTS |
|
336 void HbPopupPrivate::_q_delayedHide(HbEffect::EffectStatus status) |
|
337 { |
|
338 Q_UNUSED(status); |
|
339 |
|
340 Q_Q(HbPopup); |
|
341 |
|
342 // Apply forceHide only if the effect started successfully |
|
343 if (status.reason != Hb::EffectNotStarted) { |
|
344 forceHide(); |
|
345 } else { |
|
346 delayedHide = false; |
|
347 } |
|
348 |
|
349 if (deleteOnClose) { |
|
350 q->deleteLater(); |
|
351 } |
|
352 hidingInProgress = false; |
|
353 } |
|
354 |
|
355 void HbPopupPrivate::_q_orientationChange(Qt::Orientation orient, bool animate) |
|
356 { |
|
357 Q_UNUSED(orient); |
|
358 if (animate) { |
|
359 Q_Q(HbPopup); |
|
360 HbEffect::start(q, "HB_POPUP", "orientationswitch"); |
|
361 } |
|
362 |
|
363 } |
|
364 #endif // HB_EFFECTS |
|
365 |
|
366 void HbPopupPrivate::_q_timeoutFinished() |
|
367 { |
|
368 Q_Q(HbPopup); |
|
369 timedOut = true; |
|
370 q->close(); |
|
371 } |
|
372 |
|
373 void HbPopupPrivate::stopTimeout() |
|
374 { |
|
375 if (timeoutTimerInstance) |
|
376 timeoutTimerInstance->stop(); |
|
377 } |
|
378 |
|
379 void HbPopupPrivate::startTimeout() |
|
380 { |
|
381 if (timeout > 0) { |
|
382 timeoutTimer()->start(); |
|
383 timedOut = false; |
|
384 } |
|
385 } |
|
386 |
|
387 QTimer *HbPopupPrivate::timeoutTimer() |
|
388 { |
|
389 Q_Q(HbPopup); |
|
390 if (!timeoutTimerInstance) { |
|
391 timeoutTimerInstance = new QTimer(q); |
|
392 timeoutTimerInstance->setSingleShot(true); |
|
393 q->connect(timeoutTimerInstance, SIGNAL(timeout()), q, SLOT(_q_timeoutFinished())); |
|
394 } |
|
395 |
|
396 return timeoutTimerInstance; |
|
397 } |
|
398 |
|
399 void HbPopupPrivate::handleKeyEvent(QKeyEvent *event) |
|
400 { |
|
401 Q_Q(HbPopup); |
|
402 event->accept(); |
|
403 |
|
404 // Any key event dismisses the popup if dismissPolicy includes TapInside flag |
|
405 if (dismissPolicy & HbPopup::TapInside && !q->parentItem()) { |
|
406 q->close(); |
|
407 } |
|
408 } |
|
409 |
|
410 //returns true if popup has been added to scene here. |
|
411 bool HbPopupPrivate::addPopupToScene() |
|
412 { |
|
413 Q_Q(HbPopup); |
|
414 bool popupAdded(false); |
|
415 if (!q->parentItem()) { |
|
416 if (!q->scene() && !HbInstance::instance()->allMainWindows().isEmpty()) { |
|
417 HbInstance::instance()->allMainWindows().at(0)->scene()->addItem(q); |
|
418 popupAdded = true; |
|
419 if (backgroundItem) { |
|
420 q->scene()->addItem(backgroundItem); |
|
421 } |
|
422 } else if (q->scene() && backgroundItem && backgroundItem->scene() != q->scene()) { |
|
423 q->scene()->addItem(backgroundItem); |
|
424 } |
|
425 } |
|
426 return popupAdded; |
|
427 } |
|
428 |
|
429 void HbPopupPrivate::handleBackgroundMousePressEvent() |
|
430 { |
|
431 mousePressLocation = Background; |
|
432 } |
|
433 |
|
434 void HbPopupPrivate::handleBackgroundMouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
|
435 { |
|
436 Q_Q(HbPopup); |
|
437 |
|
438 // Handle cases only for Background or Popup originated mouse presses and when |
|
439 // any dismiss policy defined |
|
440 if (mousePressLocation != None && dismissPolicy != HbPopup::NoDismiss) { |
|
441 |
|
442 MouseEventLocationType mouseReleaseLocation = Background; |
|
443 |
|
444 if (q->contains (q->mapFromScene(event->scenePos()))) { |
|
445 mouseReleaseLocation = Popup; |
|
446 } |
|
447 |
|
448 // Mouse is released within popup |
|
449 if (mouseReleaseLocation == Popup) { |
|
450 // Handle cases only when TapInside is set |
|
451 if (dismissPolicy & HbPopup::TapInside) { |
|
452 // Close popup if mouse press is initiated within popup or TapOutside is set |
|
453 if (mousePressLocation == Popup || dismissPolicy & HbPopup::TapOutside) { |
|
454 q->close(); |
|
455 } |
|
456 } |
|
457 } |
|
458 // Mouse is released within popup background |
|
459 else { |
|
460 // Handle cases only when TapOutside is set |
|
461 if (dismissPolicy & HbPopup::TapOutside) { |
|
462 // Close popup if mouse press is initiated within popup background |
|
463 // or TapInside is set |
|
464 if (mousePressLocation == Background || dismissPolicy & HbPopup::TapInside) { |
|
465 q->close(); |
|
466 } |
|
467 } |
|
468 } |
|
469 } |
|
470 |
|
471 // reset mousePressLocation |
|
472 mousePressLocation = None; |
|
473 } |
|
474 |
|
475 |
|
476 int HbPopupPrivate::timeoutValue(HbPopup::DefaultTimeout timeout) |
|
477 { |
|
478 int count = sizeof(timeoutValues) / sizeof(timeoutValues[0]); |
|
479 if (timeout < 0 || timeout >= count) { |
|
480 return timeoutValues[HbPopup::NoTimeout].value; |
|
481 } |
|
482 return timeoutValues[timeout].value; |
|
483 } |
|
484 |
|
485 void HbPopupPrivate::forceHide() |
|
486 { |
|
487 Q_Q(HbPopup); |
|
488 |
|
489 delayedHide = false; |
|
490 q->hide(); |
|
491 delayedHide = hasEffects; |
|
492 } |
|
493 |
|
494 void HbPopupPrivate::addPopupEffects() |
|
495 { |
|
496 |
|
497 #ifdef HB_EFFECTS |
|
498 effectType = "HB_POPUP"; |
|
499 hasEffects = popupEffectsLoaded; |
|
500 if (popupEffectsLoaded) |
|
501 return; |
|
502 popupEffectsLoaded = true; |
|
503 hasEffects = HbEffectInternal::add("HB_POPUP", |
|
504 "popup_appear", |
|
505 "appear"); |
|
506 if (hasEffects) { |
|
507 hasEffects = HbEffectInternal::add("HB_POPUP", |
|
508 "popup_disappear", |
|
509 "disappear"); |
|
510 } |
|
511 if (hasEffects ) { |
|
512 hasEffects = HbEffectInternal::add("HB_POPUP", |
|
513 "dialog_rotate", |
|
514 "orientationswitch"); |
|
515 } |
|
516 #endif |
|
517 } |
|
518 |
|
519 |
|
520 void HbPopupPrivate::doSetModal( bool modal ) { |
|
521 if(backgroundItem) { |
|
522 // When the popup is modal background item must receive focus |
|
523 // events to be able to prevent last focus item losing its |
|
524 // focus |
|
525 backgroundItem->setFlag(QGraphicsItem::ItemIsFocusable, modal); |
|
526 } |
|
527 } |
|
528 |
|
529 /*! |
|
530 * Constructs a popup with given \a parent graphics item.\n |
|
531 * Note: popups with \a parent set as 0 are behaving as real popups. |
|
532 * This is actually the intended use. |
|
533 * |
|
534 * However in some situation could be useful to embedd a popup into a QGraphicsItem. |
|
535 * In this case a non zero \a parent value must be passed. |
|
536 * Popups with parent items behaving just like any other QGraphicsWidget. |
|
537 * The following features are not supported (i.e. ignored) for popup with parents: |
|
538 * |
|
539 * - modality |
|
540 * - timeout |
|
541 * - unfadedItems |
|
542 * - dismissPolicy |
|
543 * - signal aboutToClose |
|
544 */ |
|
545 HbPopup::HbPopup(QGraphicsItem *parent) : |
|
546 HbWidget(*new HbPopupPrivate,parent) |
|
547 { |
|
548 Q_D(HbPopup); |
|
549 d->q_ptr = this; |
|
550 d->init(); |
|
551 } |
|
552 |
|
553 |
|
554 /*! |
|
555 \internal |
|
556 */ |
|
557 HbPopup::HbPopup(HbPopupPrivate &dd, QGraphicsItem *parent) : |
|
558 HbWidget(dd, parent) |
|
559 { |
|
560 Q_D(HbPopup); |
|
561 d->q_ptr = this; |
|
562 d->init(); |
|
563 } |
|
564 /*! |
|
565 * Destroys the popup. |
|
566 */ |
|
567 HbPopup::~HbPopup() |
|
568 { |
|
569 Q_D(HbPopup); |
|
570 d->inDestruction = true; |
|
571 |
|
572 // Deregister popup from HbPopupManager in case hideEvent() was not called |
|
573 // before destruction |
|
574 HbGraphicsScene *hbScene = qobject_cast<HbGraphicsScene *>(scene()); |
|
575 if (hbScene) { |
|
576 hbScene->d_ptr->hidePopup(this); |
|
577 } |
|
578 |
|
579 if (d->eventLoop) { |
|
580 d->eventLoop->exit(); |
|
581 } |
|
582 if (d->backgroundItem) { |
|
583 // Set backgroundItem->popup to 0 to avoid double deletion |
|
584 // e.g. when popup is deleted by scene before its backgroundItem |
|
585 d->backgroundItem->popup = 0; |
|
586 |
|
587 // Delete the background item only and only if it's not going |
|
588 // to be cleaned up by the destructing graphics scene |
|
589 QGraphicsScene *scene = d->backgroundItem->scene(); // krazy:exclude=qclasses |
|
590 if (!scene || !scene->property("destructed").isValid()) { |
|
591 delete d->backgroundItem; |
|
592 } |
|
593 } |
|
594 } |
|
595 |
|
596 |
|
597 /*! |
|
598 * Returns the popup timeout property in milliseconds. |
|
599 * If this property is not set the deafult is HbPopup::StandardTimeout. |
|
600 * \sa setTimeout() |
|
601 */ |
|
602 int HbPopup::timeout() const |
|
603 { |
|
604 Q_D(const HbPopup); |
|
605 return d->timeout; |
|
606 } |
|
607 |
|
608 /*! |
|
609 * Sets the popup timeout property in milliseconds. |
|
610 * If timeout <= 0 then the popup is permanent and not closed automatically. |
|
611 * \sa timeout() setTimeout(HbPopup::DefaultTimeout) QGraphicsWidget::close() |
|
612 */ |
|
613 void HbPopup::setTimeout(int timeout) |
|
614 { |
|
615 Q_D(HbPopup); |
|
616 d->timeout = timeout; |
|
617 } |
|
618 |
|
619 /*! |
|
620 * It is a convenience overload of \a timeout() for setting HbPopup::DefaultTimeout values |
|
621 * to achieve common look & feel. |
|
622 * \sa enum DefaultTimeout |
|
623 * \sa timeout() setTimeout(int) QGraphicsWidget::close() |
|
624 */ |
|
625 void HbPopup::setTimeout(HbPopup::DefaultTimeout timeout) |
|
626 { |
|
627 setTimeout(HbPopupPrivate::timeoutValue(timeout)); |
|
628 } |
|
629 |
|
630 /*! |
|
631 * Returns the popup modality property. |
|
632 * A modal popup blocks any user initiated events outside of the popup |
|
633 * until it is closed. |
|
634 * \sa setModal() |
|
635 */ |
|
636 bool HbPopup::isModal() const |
|
637 { |
|
638 Q_D(const HbPopup); |
|
639 return d->modal; |
|
640 } |
|
641 |
|
642 /*! |
|
643 * Sets the popup modality property. |
|
644 * \sa isModal() |
|
645 */ |
|
646 void HbPopup::setModal(bool enabled) |
|
647 { |
|
648 Q_D(HbPopup); |
|
649 d->modal = enabled; |
|
650 d->doSetModal( d->modal ); |
|
651 } |
|
652 |
|
653 /*! |
|
654 * Sets the background of popup faded if \a fadeBackground is true otherwise |
|
655 * the background will not be faded. |
|
656 * \sa isBackgroundFaded() |
|
657 */ |
|
658 void HbPopup::setBackgroundFaded(bool fadeBackground) |
|
659 { |
|
660 Q_D(HbPopup); |
|
661 d->fadeBackground = fadeBackground; |
|
662 } |
|
663 |
|
664 /*! |
|
665 * Returns if the background of the popup is faded or not. |
|
666 * Default: true |
|
667 * \sa isBackgroundFaded() |
|
668 */ |
|
669 bool HbPopup::isBackgroundFaded() const |
|
670 { |
|
671 Q_D(const HbPopup); |
|
672 return d->backgroundItem && d->fadeBackground; |
|
673 } |
|
674 |
|
675 /*! |
|
676 * Returns the dismiss policy of the popup. |
|
677 * Default is HbPopup::TapOutside. |
|
678 * \sa setDismissPolicy() |
|
679 */ |
|
680 HbPopup::DismissPolicy HbPopup::dismissPolicy() const |
|
681 { |
|
682 Q_D(const HbPopup); |
|
683 return d->dismissPolicy; |
|
684 } |
|
685 |
|
686 /*! |
|
687 * Sets the dismiss policy property for the the popup. |
|
688 * |
|
689 * \sa dismissPolicy() |
|
690 */ |
|
691 void HbPopup::setDismissPolicy(HbPopup::DismissPolicy dismissPolicy) |
|
692 { |
|
693 Q_D(HbPopup); |
|
694 d->dismissPolicy = dismissPolicy; |
|
695 } |
|
696 |
|
697 /*! |
|
698 * Returns the frame type of the popup. |
|
699 * Default is HbPopup::Strong |
|
700 * \sa setFrameType() |
|
701 */ |
|
702 HbPopup::FrameType HbPopup::frameType() const |
|
703 { |
|
704 Q_D(const HbPopup); |
|
705 return d->frameType; |
|
706 } |
|
707 |
|
708 /*! |
|
709 * Sets the frame typeproperty for the the popup. |
|
710 * |
|
711 * \sa frameType() |
|
712 */ |
|
713 void HbPopup::setFrameType(HbPopup::FrameType frameType) |
|
714 { |
|
715 Q_D(HbPopup); |
|
716 if ( d->frameType != frameType ) { |
|
717 switch( frameType ) { |
|
718 case HbPopup::Weak: |
|
719 setBackgroundItem(HbStyle::P_Popup_background_weak); |
|
720 break; |
|
721 case HbPopup::Strong: |
|
722 default: |
|
723 setBackgroundItem(HbStyle::P_Popup_background); |
|
724 break; |
|
725 } |
|
726 d->frameType = frameType; |
|
727 updatePrimitives(); |
|
728 } |
|
729 } |
|
730 |
|
731 |
|
732 /*! @alpha |
|
733 * |
|
734 * Shows the popup as modal popup returning immediately. |
|
735 |
|
736 * Connects aboutToClose() signal to the slot specified by \a receiver and |
|
737 * \a member. The signal will be disconnected from the slot when the |
|
738 * popup is closed. |
|
739 * |
|
740 * For non modal popups, use show(). |
|
741 */ |
|
742 void HbPopup::open( QObject *receiver, const char *member ) |
|
743 { |
|
744 Q_D(HbPopup); |
|
745 connect(this, SIGNAL(aboutToClose()), receiver, member); |
|
746 d->receiverToDisconnectOnClose = receiver; |
|
747 d->memberToDisconnectOnClose = member; |
|
748 |
|
749 #if needed |
|
750 // Ungrab the mouse if it is currently grabbed |
|
751 // todo; currently needed menus to work ok, otherwise: |
|
752 // - quick multiple presses on menuitem causes multiple actions (menu relaunch?) |
|
753 // - closing menu with titlepane needs multiple presses (menu relaunch?) |
|
754 // Ungrab was removed when trying to fix problem when button pressed()-signal |
|
755 // was connected to menu launch. Button did not get anymore mouse release event. |
|
756 if (scene()) { |
|
757 QGraphicsItem *item = scene()->mouseGrabberItem(); |
|
758 if (item) { |
|
759 item->ungrabMouse(); |
|
760 } |
|
761 } |
|
762 #endif |
|
763 show(); |
|
764 } |
|
765 |
|
766 |
|
767 /*! |
|
768 \deprecated HbPopup::exec() |
|
769 is deprecated. Please use HbPopup::show() or |
|
770 void HbPopup::open( QObject *receiver, const char *member ) instead. |
|
771 * |
|
772 * Executes the popup synchronously. |
|
773 * Note: when popup is executed syncronously it is always modal. |
|
774 * This function is deprecated. use \sa open() or \sa show() instead. |
|
775 */ |
|
776 void HbPopup::exec() |
|
777 { |
|
778 // Q_ASSERT(false); |
|
779 Q_D(HbPopup); |
|
780 |
|
781 HbMainWindow* w(mainWindow()); |
|
782 if (w) { |
|
783 disconnect(w, SIGNAL(aboutToChangeOrientation(Qt::Orientation, bool)), this, SLOT(_q_orientationChange(Qt::Orientation, bool))); |
|
784 connect( w, SIGNAL(aboutToChangeOrientation(Qt::Orientation, bool)), this, SLOT(_q_orientationChange(Qt::Orientation, bool)) ); |
|
785 } |
|
786 |
|
787 if (!d->eventLoop) { |
|
788 // Prevent deleting popup in eventloop |
|
789 bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose); |
|
790 setAttribute(Qt::WA_DeleteOnClose, false); |
|
791 |
|
792 // Set popup to modal before eventloop |
|
793 bool wasShowModal = isModal(); |
|
794 setModal(true); |
|
795 |
|
796 show(); |
|
797 |
|
798 // Ungrab the mouse if it is currently grabbed |
|
799 // todo; currently needed menus to work ok, otherwise: |
|
800 // - quick multiple presses on menuitem causes multiple actions (menu relaunch?) |
|
801 // - closing menu with titlepane needs multiple presses (menu relaunch?) |
|
802 // Ungrab was removed when trying to fix problem when button pressed()-signal |
|
803 // was connected to menu launch. Button did not get anymore mouse release event. |
|
804 if (scene()) { |
|
805 QGraphicsItem *item = scene()->mouseGrabberItem(); |
|
806 if (item) { |
|
807 item->ungrabMouse(); |
|
808 } |
|
809 } |
|
810 |
|
811 QEventLoop eventLoop; |
|
812 d->eventLoop = &eventLoop; |
|
813 QPointer<QObject> guard = this; |
|
814 d->eventLoop->exec(); |
|
815 if (guard.isNull()) { |
|
816 return; |
|
817 } |
|
818 d->eventLoop = 0; |
|
819 |
|
820 // Reset modality |
|
821 setModal(wasShowModal); |
|
822 |
|
823 if (deleteOnClose) { |
|
824 delete this; |
|
825 } |
|
826 } else { |
|
827 qWarning("HbPopup::exec: Recursive call detected"); |
|
828 } |
|
829 } |
|
830 |
|
831 /*! |
|
832 \reimp |
|
833 */ |
|
834 QVariant HbPopup::itemChange ( GraphicsItemChange change, const QVariant & value ) |
|
835 { |
|
836 Q_D(HbPopup); |
|
837 |
|
838 if (change == QGraphicsItem::ItemVisibleChange) { |
|
839 if (value.toBool()) { |
|
840 if(!d->hasEffects){ |
|
841 d->addPopupEffects(); |
|
842 } |
|
843 if (!d->aboutToShowSignalGuard) |
|
844 { |
|
845 d->aboutToShowSignalGuard = true; |
|
846 emit aboutToShow(); |
|
847 } |
|
848 // Note: when visibility changes to "visible" base class implementation needs |
|
849 // to be called otherwise showEvent() is not called. |
|
850 |
|
851 } else { |
|
852 d->aboutToShowSignalGuard = false; |
|
853 if (!d->hidingInProgress) { |
|
854 emit aboutToHide(); |
|
855 } |
|
856 |
|
857 if (d->delayedHide && // about to hide and we wanna delay hiding |
|
858 d->hasEffects && !parentItem()) { // only for popup without parent |
|
859 if (!d->hidingInProgress) { // Prevent reentrance |
|
860 d->hidingInProgress = true; |
|
861 #ifdef HB_EFFECTS |
|
862 QRectF extRect(0.0, |
|
863 -boundingRect().height(), |
|
864 boundingRect().width(), |
|
865 0); |
|
866 if (!HbEffect::start(this, d->effectType, "disappear", |
|
867 this, "_q_delayedHide", |
|
868 QVariant(), extRect)) { |
|
869 d->delayedHide = false; |
|
870 } |
|
871 #endif |
|
872 } |
|
873 if (d->delayedHide) { |
|
874 return true; |
|
875 } else { |
|
876 d->delayedHide = d->hasEffects; |
|
877 d->hidingInProgress = false; |
|
878 // fallback to base class imp |
|
879 } |
|
880 } |
|
881 } |
|
882 } else if (change == QGraphicsItem::ItemSceneHasChanged) { |
|
883 HbMainWindow* w(mainWindow()); |
|
884 if ( w ){ |
|
885 disconnect(this, SLOT(handlePopupPos())); |
|
886 connect( w, SIGNAL(orientationChanged(Qt::Orientation)), |
|
887 this, SLOT(handlePopupPos()) ); |
|
888 } |
|
889 } |
|
890 return HbWidget::itemChange(change, value); |
|
891 } |
|
892 |
|
893 /*! |
|
894 * Handles the popup position when Orientation changes |
|
895 */ |
|
896 void HbPopup::handlePopupPos() |
|
897 { |
|
898 QEvent userEvent(QEvent::ContextMenu); |
|
899 QCoreApplication::sendEvent(this, &userEvent); |
|
900 } |
|
901 |
|
902 /*! |
|
903 \reimp |
|
904 */ |
|
905 void HbPopup::mousePressEvent(QGraphicsSceneMouseEvent *event ) |
|
906 { |
|
907 Q_D(HbPopup); |
|
908 |
|
909 Q_UNUSED(event); |
|
910 |
|
911 d->mousePressLocation = HbPopupPrivate::Popup; |
|
912 |
|
913 // We need to reimplement this function otherwise this events will be |
|
914 // ignored by default and we wont get further mouse events |
|
915 // not even mouseReleaseEvent. See doc of QGraphicsItem::mousePressEvent() |
|
916 // for more info. |
|
917 QGraphicsItem::mousePressEvent(event); |
|
918 |
|
919 // Event has to be accepted cause QGraphicsItem::mousePressEvent can mark it |
|
920 // to ignored |
|
921 event->accept(); |
|
922 } |
|
923 |
|
924 /*! |
|
925 \reimp |
|
926 */ |
|
927 void HbPopup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event ) |
|
928 { |
|
929 QGraphicsItem::mouseReleaseEvent(event); |
|
930 event->accept(); |
|
931 // Note: Mouse release event is always handled in handleBackgroundMouseReleaseEvent |
|
932 } |
|
933 |
|
934 /*! |
|
935 \reimp |
|
936 */ |
|
937 void HbPopup::keyPressEvent(QKeyEvent *event) |
|
938 { |
|
939 Q_D(HbPopup); |
|
940 d->handleKeyEvent(event); |
|
941 } |
|
942 |
|
943 /*! |
|
944 \reimp |
|
945 */ |
|
946 // |
|
947 // Shows the popup with an animation and starts the timer to dismiss the popup, |
|
948 // unless it is a permanent popup. |
|
949 // |
|
950 void HbPopup::showEvent(QShowEvent *event) |
|
951 { |
|
952 Q_D(HbPopup); |
|
953 |
|
954 HbWidget::showEvent(event); |
|
955 |
|
956 // Only for popup without parent |
|
957 // Note: |
|
958 // popups without parent are treated as popups i.e.: |
|
959 // - can have background item |
|
960 // - timeout |
|
961 // - and registered to HbPopupManager |
|
962 // otherwise popup is treated as normal widget |
|
963 if(d->duplicateShowEvent){ |
|
964 d->duplicateShowEvent = false; |
|
965 return; |
|
966 } |
|
967 if (!parentItem()) { |
|
968 //check if popup needs to be added to scene.This can result in duplciate show event, |
|
969 // if popup is added to scene here. |
|
970 if(d->addPopupToScene()) |
|
971 d->duplicateShowEvent = true; |
|
972 |
|
973 // Popup clears closed state |
|
974 d->closed = false; |
|
975 if (d->backgroundItem) { |
|
976 d->backgroundItem->setVisible(true); |
|
977 d->backgroundItem->setAcceptHoverEvents(isModal()); |
|
978 // Let the background be a panel if the popup is one |
|
979 // However if the popup is not modal we don't want the background |
|
980 // to be a panel. A panel provides contained focus handling |
|
981 if ((flags() & QGraphicsItem::ItemIsPanel) && isModal()) { |
|
982 d->backgroundItem->setFlag(QGraphicsItem::ItemIsPanel); |
|
983 } |
|
984 } |
|
985 if (qobject_cast<HbGraphicsScene *>(scene())) { |
|
986 qobject_cast<HbGraphicsScene *>(scene())->d_ptr->showPopup(this); |
|
987 HbWidgetFeedback::triggered(this, Hb::InstantPopupOpened); |
|
988 } |
|
989 |
|
990 /*if(d->hasEffects && boundingRect().isValid()) { |
|
991 |
|
992 #ifdef HB_EFFECTS |
|
993 QRectF extRect(0.0, |
|
994 -boundingRect().height(), |
|
995 boundingRect().width(), |
|
996 0); |
|
997 HbEffect::start(this, d->effectType, "appear", 0, 0, QVariant(), extRect); |
|
998 #endif//HB_EFFECTS |
|
999 d->mStartEffect = false; |
|
1000 } else { |
|
1001 d->mStartEffect = true; |
|
1002 }*/ |
|
1003 |
|
1004 //workaround |
|
1005 resetTransform(); |
|
1006 setOpacity(1); |
|
1007 //workaround ends |
|
1008 |
|
1009 // delay hiding if effects are enabled |
|
1010 d->delayedHide = d->hasEffects; |
|
1011 |
|
1012 // If it is not permanent launch a timer for closing the popup |
|
1013 if (0 < d->timeout) { |
|
1014 d->timeoutTimer()->setInterval(d->timeout); |
|
1015 d->timeoutTimer()->start(); |
|
1016 } |
|
1017 } |
|
1018 } |
|
1019 |
|
1020 /*! |
|
1021 \reimp |
|
1022 */ |
|
1023 void HbPopup::hideEvent(QHideEvent *event) |
|
1024 { |
|
1025 Q_D(HbPopup); |
|
1026 |
|
1027 HbWidget::hideEvent(event); |
|
1028 |
|
1029 // Only for popup without parent |
|
1030 if (!parentItem()) { |
|
1031 if (d->backgroundItem) { |
|
1032 d->backgroundItem->setVisible(false); |
|
1033 } |
|
1034 qobject_cast<HbGraphicsScene *>(scene())->d_ptr->hidePopup(this); |
|
1035 } |
|
1036 |
|
1037 HbWidgetFeedback::triggered(this, Hb::InstantPopupClosed); |
|
1038 if (d->eventLoop) { |
|
1039 d->eventLoop->exit(); |
|
1040 } |
|
1041 |
|
1042 d->doSetModal( d->modal ); |
|
1043 |
|
1044 } |
|
1045 |
|
1046 /*! |
|
1047 \reimp |
|
1048 */ |
|
1049 void HbPopup::resizeEvent( QGraphicsSceneResizeEvent * event ) |
|
1050 { |
|
1051 HbWidget::resizeEvent(event); |
|
1052 updatePrimitives(); |
|
1053 } |
|
1054 |
|
1055 /*! |
|
1056 \reimp |
|
1057 */ |
|
1058 void HbPopup::closeEvent ( QCloseEvent * event ) |
|
1059 { |
|
1060 Q_D(HbPopup); |
|
1061 d->stopTimeout(); |
|
1062 // Only for popup without parent |
|
1063 if (!d->closed && !parentItem()) { |
|
1064 // Popup goes to closed state |
|
1065 d->closed = true; |
|
1066 |
|
1067 emit aboutToClose(); |
|
1068 |
|
1069 // prevent delete on close before effects are finished |
|
1070 if (d->hasEffects && isVisible()) { |
|
1071 d->deleteOnClose = testAttribute(Qt::WA_DeleteOnClose); |
|
1072 setAttribute(Qt::WA_DeleteOnClose,false); |
|
1073 } |
|
1074 HbToolTip::hideText(qobject_cast<HbGraphicsScene *>(scene())); |
|
1075 } |
|
1076 if (d->receiverToDisconnectOnClose) { |
|
1077 disconnect(this, SIGNAL(aboutToClose()), |
|
1078 d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose); |
|
1079 d->receiverToDisconnectOnClose = 0; |
|
1080 } |
|
1081 d->memberToDisconnectOnClose.clear(); |
|
1082 HbWidget::closeEvent(event); |
|
1083 } |
|
1084 |
|
1085 /*! |
|
1086 \reimp |
|
1087 */ |
|
1088 bool HbPopup::event(QEvent *event) |
|
1089 { |
|
1090 /*Q_D(HbPopup); |
|
1091 if (event->type() == QEvent::GraphicsSceneResize) { |
|
1092 //Workaround when showing first time |
|
1093 #ifdef HB_EFFECTS |
|
1094 if(d->mStartEffect && boundingRect().isValid()) { |
|
1095 QRectF extRect(0.0, |
|
1096 -boundingRect().height(), |
|
1097 boundingRect().width(), |
|
1098 0); |
|
1099 HbEffect::start(this, d->effectType, "appear", 0, 0, QVariant(), extRect); |
|
1100 d->mStartEffect = false; |
|
1101 } |
|
1102 #endif//HB_EFFECTS |
|
1103 //workaround ends |
|
1104 }*/ |
|
1105 return HbWidget::event(event); |
|
1106 } |
|
1107 |
|
1108 |
|
1109 /*! |
|
1110 Sets preferred position\a position for popup with \a placement |
|
1111 as origin. |
|
1112 |
|
1113 \param position is the position at which the popup is shown. |
|
1114 \param placement is the corner or edge which \a position refers to |
|
1115 |
|
1116 Example usage: |
|
1117 \code |
|
1118 HbDialog popup; |
|
1119 ... |
|
1120 popup.setPreferredPosition( QPointF(x,y), HbPopupBase::BottomEdgeCenter ); |
|
1121 popup.exec(); |
|
1122 \endcode |
|
1123 |
|
1124 */ |
|
1125 |
|
1126 void HbPopup::setPreferredPos( const QPointF& preferredPos, |
|
1127 HbPopup::Placement placement ) |
|
1128 |
|
1129 { |
|
1130 Q_D(HbPopup); |
|
1131 bool layoutFlag = false; |
|
1132 if (d->preferredPos != preferredPos ) { |
|
1133 d->preferredPos = preferredPos; |
|
1134 layoutFlag = true; |
|
1135 } |
|
1136 if (d->placement != placement) { |
|
1137 d->placement = placement; |
|
1138 layoutFlag = true; |
|
1139 } |
|
1140 d->preferredPosSet = true; |
|
1141 //If position updated, informing layoutproxy with layoutrequest |
|
1142 if (layoutFlag) { |
|
1143 QApplication::postEvent(this, new QEvent(QEvent::LayoutRequest)); |
|
1144 } |
|
1145 } |
|
1146 |
|
1147 #include "moc_hbpopup.cpp" |