|
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 "hbdialog.h" |
|
27 #include "hbdialog_p.h" |
|
28 #include "hbinstance.h" |
|
29 #include "hbaction.h" |
|
30 #include "hbstyleoptionpopup.h" |
|
31 #include "hbdeviceprofile.h" |
|
32 #include "hbevent.h" |
|
33 #include "hbtoolbar_p.h" |
|
34 |
|
35 #include <QPainter> |
|
36 #include <QGraphicsSceneMouseEvent> |
|
37 #include <QStyleOptionGraphicsItem> |
|
38 #include <QShowEvent> |
|
39 #include <QHideEvent> |
|
40 #include <QEventLoop> |
|
41 #include <QPointer> |
|
42 #include <QDebug> |
|
43 #include <QGraphicsLinearLayout> |
|
44 #include <QApplication> // krazy:exclude=qclasses |
|
45 |
|
46 #include <hbfeedbackmanager.h> |
|
47 |
|
48 #ifdef HB_EFFECTS |
|
49 #include "hbeffectinternal_p.h" |
|
50 #define HB_POPUP_ITEM_TYPE "HB_POPUP" |
|
51 #endif |
|
52 |
|
53 /*! |
|
54 @stable |
|
55 @hbcore |
|
56 \class HbDialog |
|
57 \brief HbDialog is a base class for different popup notes in Hb library. |
|
58 |
|
59 \image html hbpopup.png A popup with a header widget, a list as a content widget, |
|
60 and two action buttons. |
|
61 |
|
62 HbDialog is a concrete class. The content for a custom popup is implemented in |
|
63 a separate widget, which is set to the popup with method setContentWidget(). |
|
64 |
|
65 Lastly shown popup is always positioned in Z order on the the top of already visible popups. |
|
66 A popup can be permanent or automatically dismissed after a time-out. |
|
67 Modal popups interrupt any other user interaction outside of the popup while they are visible, |
|
68 whereas non-modal popups do not. |
|
69 |
|
70 An example of how to create a simple modal popup and show it. |
|
71 \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,13} |
|
72 |
|
73 An example of how to create a non-modal popup and show it. |
|
74 \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,26} |
|
75 */ |
|
76 |
|
77 /*! |
|
78 \reimp |
|
79 \fn int HbDialog::type() const |
|
80 */ |
|
81 |
|
82 HbDialogPrivate::HbDialogPrivate( ) : |
|
83 contentWidget(0), |
|
84 headingWidget(0), |
|
85 mainLayout(new QGraphicsLinearLayout(Qt::Vertical)), |
|
86 primaryAction(0), |
|
87 secondaryAction(0), |
|
88 closingAction(0), |
|
89 toolBar(0) |
|
90 { |
|
91 } |
|
92 |
|
93 HbDialogPrivate::~HbDialogPrivate() |
|
94 { |
|
95 } |
|
96 |
|
97 void HbDialogPrivate::init() |
|
98 { |
|
99 Q_Q(HbDialog); |
|
100 |
|
101 // Content is responsible of adding spacings & margins |
|
102 mainLayout->setSpacing(0); |
|
103 mainLayout->setContentsMargins(0,0,0,0); |
|
104 |
|
105 q->setLayout(mainLayout); |
|
106 mainLayout->setMinimumSize(0, 0); |
|
107 } |
|
108 |
|
109 void HbDialogPrivate::setWidget(int layoutIndex, QGraphicsWidget *&destWidget, QGraphicsWidget *widget) |
|
110 { |
|
111 Q_Q(HbDialog); |
|
112 if (destWidget != widget) { |
|
113 if (destWidget) { |
|
114 mainLayout->removeItem(destWidget); |
|
115 delete destWidget; |
|
116 destWidget = 0; |
|
117 } |
|
118 if (widget) { |
|
119 destWidget = widget; |
|
120 destWidget->setParentItem(q); |
|
121 mainLayout->insertItem(layoutIndex, widget); |
|
122 mainLayout->setAlignment(widget, Qt::AlignCenter); |
|
123 } |
|
124 |
|
125 doLayout(); |
|
126 } |
|
127 } |
|
128 |
|
129 /* |
|
130 Relayouts the popup. If expandSize is true it the new calculated size of the popup |
|
131 cannot be smaller than the current size. |
|
132 */ |
|
133 void HbDialogPrivate::doLayout() |
|
134 { |
|
135 Q_Q(HbDialog); |
|
136 if(q->mainWindow() && contentWidget) |
|
137 { |
|
138 if ( q->mainWindow()->layoutDirection() != contentWidget->layoutDirection() ) { |
|
139 contentWidget->setLayoutDirection(q->mainWindow()->layoutDirection()); |
|
140 } |
|
141 } |
|
142 |
|
143 if (q->mainWindow() && headingWidget) { |
|
144 if (q->mainWindow()->layoutDirection() != headingWidget->layoutDirection()) { |
|
145 headingWidget->setLayoutDirection(q->mainWindow()->layoutDirection()); |
|
146 } |
|
147 } |
|
148 |
|
149 q->updateGeometry(); |
|
150 } |
|
151 |
|
152 |
|
153 /*! |
|
154 * Constructs a popup with given \a parent graphics item.\n |
|
155 * Note: popups with \a parent set as 0 are behaving as real popups. |
|
156 * This is actually the intended use. |
|
157 * |
|
158 * However in some situation could be useful to embedd a popup into a QGraphicsItem. |
|
159 * In this case a non zero \a parent value must be passed. |
|
160 * Popups with parent items behaving just like any other QGraphicsWidget. |
|
161 * The following features are not supported (i.e. ignored) for popup with parents: |
|
162 * |
|
163 * - modality |
|
164 * - timeout |
|
165 * - unfadedItems |
|
166 * - dismissPolicy |
|
167 * - signal aboutToClose |
|
168 */ |
|
169 HbDialog::HbDialog(QGraphicsItem *parent) : |
|
170 HbPopup(*new HbDialogPrivate, parent) |
|
171 { |
|
172 Q_D(HbDialog); |
|
173 d->q_ptr = this; |
|
174 d->init(); |
|
175 } |
|
176 |
|
177 /*! |
|
178 \internal |
|
179 */ |
|
180 HbDialog::HbDialog(HbDialogPrivate &dd, QGraphicsItem *parent) : |
|
181 HbPopup(dd, parent) |
|
182 { |
|
183 Q_D(HbDialog); |
|
184 d->q_ptr = this; |
|
185 d->init(); |
|
186 } |
|
187 |
|
188 /*! |
|
189 * Destroys the popup. |
|
190 */ |
|
191 HbDialog::~HbDialog() |
|
192 { |
|
193 } |
|
194 |
|
195 /*! |
|
196 @beta |
|
197 * It returns the widget which is being added to the heading area |
|
198 * \sa setHeadingWidget() |
|
199 */ |
|
200 QGraphicsWidget * HbDialog::headingWidget() const |
|
201 { |
|
202 Q_D(const HbDialog); |
|
203 return (d->headingWidget); |
|
204 } |
|
205 |
|
206 /*! |
|
207 @beta |
|
208 * Adds \a widget to the heading area. Ownership of the widget is transferred |
|
209 * to popup. If \a headingWidget is 0 the heading widget is removed. |
|
210 * \sa headingWidget() |
|
211 */ |
|
212 void HbDialog::setHeadingWidget(QGraphicsWidget *headingWidget) |
|
213 { |
|
214 Q_D(HbDialog); |
|
215 HbStyle::setItemName(headingWidget,"heading"); |
|
216 d->setWidget(0, d->headingWidget, headingWidget); |
|
217 } |
|
218 |
|
219 /*! |
|
220 * Returns the content widget property of the popup. |
|
221 * HbDialog only draws a bordered rect, the rest is drawn by the content widget. |
|
222 * \sa setContentWidget() |
|
223 */ |
|
224 QGraphicsWidget *HbDialog::contentWidget() const |
|
225 { |
|
226 Q_D(const HbDialog); |
|
227 return d->contentWidget; |
|
228 } |
|
229 |
|
230 /*! |
|
231 * Sets the content widget property of the popup. |
|
232 * HbDialog only draws a bordered rect, the rest is drawn by the content widget. |
|
233 * Ownership of the widget is transferred |
|
234 * to popup. If \a contentWidget is 0 the content widget is removed. |
|
235 * \sa contentWidget() |
|
236 */ |
|
237 void HbDialog::setContentWidget(QGraphicsWidget *contentWidget) |
|
238 { |
|
239 Q_D(HbDialog); |
|
240 HbStyle::setItemName(contentWidget,"content"); |
|
241 d->setWidget((d->headingWidget?1:0), d->contentWidget, contentWidget); |
|
242 } |
|
243 |
|
244 /*! |
|
245 * It returns the primary action added to the control area |
|
246 * \sa setPrimaryAction() |
|
247 */ |
|
248 HbAction* HbDialog::primaryAction() const |
|
249 { |
|
250 Q_D(const HbDialog); |
|
251 return d->primaryAction; |
|
252 } |
|
253 |
|
254 /*! |
|
255 * It adds the given action to the control area. |
|
256 * It is added to the left side of the control area if the layout direction of the application |
|
257 * is left-to-right and in the vice-versa if the layout direction of the application |
|
258 * is right-to-left. |
|
259 * \sa primaryAction() |
|
260 */ |
|
261 void HbDialog::setPrimaryAction(HbAction *action) |
|
262 { |
|
263 Q_D(HbDialog); |
|
264 if (d->primaryAction && action != d->primaryAction) { |
|
265 removeAction(d->primaryAction); |
|
266 } |
|
267 d->primaryAction = action; |
|
268 QAction *before = 0; //krazy:exclude=qclasses |
|
269 if (actions().count()) { |
|
270 before = actions().first(); |
|
271 } |
|
272 insertAction(before, action); |
|
273 } |
|
274 |
|
275 /*! |
|
276 * It returns the secondary action added to the control area |
|
277 * \sa setSecondaryAction() |
|
278 */ |
|
279 HbAction* HbDialog::secondaryAction() const |
|
280 { |
|
281 Q_D(const HbDialog); |
|
282 return(d->secondaryAction); |
|
283 } |
|
284 |
|
285 /*! |
|
286 * It adds the given action to the control area. |
|
287 * It is added to the right side of the control area if the layout direction of the application |
|
288 * is left-to-right and in the vice-versa if the layout direction of the application |
|
289 * is right-to-left. |
|
290 * \sa secondaryAction() |
|
291 */ |
|
292 void HbDialog::setSecondaryAction(HbAction *action) |
|
293 { |
|
294 Q_D(HbDialog); |
|
295 if (d->secondaryAction && action != d->secondaryAction) { |
|
296 removeAction(d->secondaryAction); |
|
297 } |
|
298 d->secondaryAction = action; |
|
299 addAction(action); |
|
300 } |
|
301 |
|
302 /*! |
|
303 \deprecated HbDialog::exec() |
|
304 is deprecated. Please use HbDialog::open( QObject* receiver, const char* member ) instead. |
|
305 * |
|
306 * Executes the popup synchronously. |
|
307 * Note: when popup is executed syncronously it is always modal. |
|
308 */ |
|
309 HbAction* HbDialog::exec() |
|
310 { |
|
311 Q_D(HbDialog); |
|
312 |
|
313 HbAction *action = 0; |
|
314 QPointer<QObject> guard = this; |
|
315 HbPopup::exec(); |
|
316 if (!guard.isNull()) { |
|
317 action = d->closingAction; |
|
318 d->closingAction = 0; |
|
319 } |
|
320 return action; |
|
321 } |
|
322 |
|
323 /*! @alpha |
|
324 * |
|
325 * Shows the dialog as modal dialog returning immediately. |
|
326 |
|
327 * Connects finished(HbAction*) signal to the slot specified by \a receiver and |
|
328 * \a member. The signal will be disconnected from the slot when the |
|
329 * popup is closed. |
|
330 * |
|
331 * For non modal popups, use show(). |
|
332 */ |
|
333 |
|
334 void HbDialog::open( QObject* receiver, const char* member ) |
|
335 { |
|
336 Q_D(HbDialog); |
|
337 if ( receiver && member ) { |
|
338 connect( this, SIGNAL(finished(HbAction*)), receiver, member ); |
|
339 d->receiverToDisconnectOnClose = receiver; |
|
340 d->memberToDisconnectOnClose = member; |
|
341 } else { |
|
342 d->receiverToDisconnectOnClose = 0; |
|
343 d->memberToDisconnectOnClose.clear(); |
|
344 } |
|
345 HbPopup::open(); |
|
346 } |
|
347 |
|
348 /*! |
|
349 * \reimp |
|
350 */ |
|
351 // |
|
352 // Sets the focus to its content widget. |
|
353 // |
|
354 void HbDialog::focusInEvent(QFocusEvent *event) |
|
355 { |
|
356 Q_UNUSED(event); |
|
357 if(contentWidget()) { |
|
358 contentWidget()->setFocus(); |
|
359 } |
|
360 } |
|
361 |
|
362 /*! |
|
363 \reimp |
|
364 */ |
|
365 void HbDialog::closeEvent ( QCloseEvent * event ) |
|
366 { |
|
367 Q_D(HbDialog); |
|
368 |
|
369 HbAction *closingAction = qobject_cast<HbAction *>(sender()); |
|
370 if (closingAction && actions().contains(closingAction)) { |
|
371 d->closingAction = closingAction; |
|
372 emit finished( d->closingAction ); |
|
373 } else { |
|
374 HbAction* nullAction(0); |
|
375 emit finished( nullAction ); |
|
376 } |
|
377 |
|
378 HbPopup::closeEvent(event); |
|
379 } |
|
380 |
|
381 /*! |
|
382 \reimp |
|
383 */ |
|
384 void HbDialog::changeEvent(QEvent *event) |
|
385 { |
|
386 Q_D(HbDialog); |
|
387 if (event->type() == QEvent::StyleChange || |
|
388 event->type() == QEvent::LayoutDirectionChange) { |
|
389 d->doLayout(); |
|
390 } |
|
391 |
|
392 HbPopup::changeEvent(event); |
|
393 } |
|
394 |
|
395 /*! |
|
396 \reimp |
|
397 */ |
|
398 bool HbDialog::event(QEvent *event) |
|
399 { |
|
400 Q_D(HbDialog); |
|
401 event->accept(); |
|
402 |
|
403 if (event->type() == QEvent::ActionAdded) { |
|
404 if (!d->toolBar) { |
|
405 // TODO: HbToolBar private interface should make it possible to choose |
|
406 // different graphics for tool buttons. |
|
407 d->toolBar = new HbToolBar(); |
|
408 HbStyle::setItemName(d->toolBar ,"controls"); |
|
409 d->toolBar->setParentItem(this); |
|
410 d->toolBar->setOrientation(Qt::Horizontal); |
|
411 HbToolBarPrivate::d_ptr(d->toolBar)->mDialogToolBar = true; |
|
412 // prevent stretching buttons, should the content be small |
|
413 // but dialog size forcibly large |
|
414 d->mainLayout->addStretch(); |
|
415 d->mainLayout->addItem(d->toolBar); |
|
416 } |
|
417 QActionEvent *actionEvent = static_cast<QActionEvent *>(event); |
|
418 d->toolBar->insertAction (actionEvent->before(), actionEvent->action()); |
|
419 if (!parentItem()) { // only for popup without parent |
|
420 connect(actionEvent->action(), SIGNAL(triggered()), this, SLOT(close())); |
|
421 } |
|
422 d->doLayout(); |
|
423 return true; |
|
424 |
|
425 } else if (event->type() == QEvent::ActionRemoved) { |
|
426 |
|
427 QActionEvent *actionEvent = static_cast<QActionEvent *>(event); |
|
428 // remove primary or secondary action if set |
|
429 if (actionEvent->action() == d->primaryAction) { |
|
430 d->primaryAction = 0; |
|
431 } else if (actionEvent->action() == d->secondaryAction) { |
|
432 d->secondaryAction = 0; |
|
433 } |
|
434 disconnect(actionEvent->action(), 0, this, 0); |
|
435 |
|
436 if (d->toolBar) { |
|
437 d->toolBar->removeAction(actionEvent->action()); |
|
438 if (!d->toolBar->actions().count()) { |
|
439 d->mainLayout->removeItem(d->toolBar); |
|
440 d->toolBar->deleteLater(); |
|
441 d->toolBar = 0; |
|
442 } |
|
443 } |
|
444 d->doLayout(); |
|
445 return true; |
|
446 |
|
447 } else if (event->type() == HbEvent::LayoutRequest) { |
|
448 if (d->toolBar |
|
449 && mainWindow() |
|
450 && d->toolBar->layoutDirection() != mainWindow()->layoutDirection() |
|
451 && !d->toolBar->testAttribute(Qt::WA_SetLayoutDirection)) { |
|
452 d->toolBar->setLayoutDirection(mainWindow()->layoutDirection()); |
|
453 d->toolBar->setAttribute(Qt::WA_SetLayoutDirection, false); |
|
454 } |
|
455 d->doLayout(); |
|
456 } |
|
457 return HbPopup::event(event); |
|
458 } |
|
459 |
|
460 #include "moc_hbdialog.cpp" |