39 ** |
39 ** |
40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include "qapplication.h" |
42 #include "qapplication.h" |
43 #include "qevent.h" |
43 #include "qevent.h" |
44 #ifdef Q_WS_S60 |
44 #include "qbitmap.h" |
45 #include "qstyle.h" |
|
46 #include "private/qt_s60_p.h" |
|
47 #endif |
|
48 #include "private/qsoftkeymanager_p.h" |
45 #include "private/qsoftkeymanager_p.h" |
49 #include "private/qobject_p.h" |
46 #include "private/qobject_p.h" |
|
47 #include "private/qsoftkeymanager_common_p.h" |
|
48 |
|
49 #ifdef Q_WS_S60 |
|
50 #include "private/qsoftkeymanager_s60_p.h" |
|
51 #endif |
50 |
52 |
51 #ifndef QT_NO_SOFTKEYMANAGER |
53 #ifndef QT_NO_SOFTKEYMANAGER |
52 QT_BEGIN_NAMESPACE |
54 QT_BEGIN_NAMESPACE |
53 |
55 |
54 #ifdef Q_WS_S60 |
|
55 static const int s60CommandStart = 6000; |
|
56 #endif |
|
57 |
|
58 class QSoftKeyManagerPrivate : public QObjectPrivate |
|
59 { |
|
60 Q_DECLARE_PUBLIC(QSoftKeyManager) |
|
61 |
|
62 public: |
|
63 static void updateSoftKeys_sys(const QList<QAction*> &softKeys); |
|
64 |
|
65 private: |
|
66 QHash<QAction*, Qt::Key> keyedActions; |
|
67 static QSoftKeyManager *self; |
|
68 static QWidget *softKeySource; |
|
69 }; |
|
70 |
|
71 QWidget *QSoftKeyManagerPrivate::softKeySource = 0; |
|
72 QSoftKeyManager *QSoftKeyManagerPrivate::self = 0; |
56 QSoftKeyManager *QSoftKeyManagerPrivate::self = 0; |
73 |
57 |
74 const char *QSoftKeyManager::standardSoftKeyText(StandardSoftKey standardKey) |
58 const char *QSoftKeyManager::standardSoftKeyText(StandardSoftKey standardKey) |
75 { |
59 { |
76 const char *softKeyText = 0; |
60 const char *softKeyText = 0; |
103 QSoftKeyManagerPrivate::self = new QSoftKeyManager; |
87 QSoftKeyManagerPrivate::self = new QSoftKeyManager; |
104 |
88 |
105 return QSoftKeyManagerPrivate::self; |
89 return QSoftKeyManagerPrivate::self; |
106 } |
90 } |
107 |
91 |
108 QSoftKeyManager::QSoftKeyManager() : QObject(*(new QSoftKeyManagerPrivate), 0) |
92 QSoftKeyManager::QSoftKeyManager() : |
|
93 #ifdef Q_WS_S60 |
|
94 QObject(*(new QSoftKeyManagerPrivateS60), 0) |
|
95 #else |
|
96 QObject(*(new QSoftKeyManagerPrivate), 0) |
|
97 #endif |
109 { |
98 { |
110 } |
99 } |
111 |
100 |
112 QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) |
101 QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) |
113 { |
102 { |
114 const char* text = standardSoftKeyText(standardKey); |
103 const char* text = standardSoftKeyText(standardKey); |
115 QAction *action = new QAction(QSoftKeyManager::tr(text), actionWidget); |
104 QAction *action = new QAction(QSoftKeyManager::tr(text), actionWidget); |
116 QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; |
105 QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; |
117 switch (standardKey) { |
106 switch (standardKey) { |
|
107 case MenuSoftKey: // FALL-THROUGH |
|
108 action->setProperty(MENU_ACTION_PROPERTY, QVariant(true)); // TODO: can be refactored away to use _q_action_menubar |
118 case OkSoftKey: |
109 case OkSoftKey: |
119 case SelectSoftKey: |
110 case SelectSoftKey: |
120 case DoneSoftKey: |
111 case DoneSoftKey: |
121 case MenuSoftKey: |
|
122 softKeyRole = QAction::PositiveSoftKey; |
112 softKeyRole = QAction::PositiveSoftKey; |
123 break; |
113 break; |
124 case CancelSoftKey: |
114 case CancelSoftKey: |
125 softKeyRole = QAction::NegativeSoftKey; |
115 softKeyRole = QAction::NegativeSoftKey; |
126 break; |
116 break; |
173 { |
163 { |
174 QEvent *event = new QEvent(QEvent::UpdateSoftKeys); |
164 QEvent *event = new QEvent(QEvent::UpdateSoftKeys); |
175 QApplication::postEvent(QSoftKeyManager::instance(), event); |
165 QApplication::postEvent(QSoftKeyManager::instance(), event); |
176 } |
166 } |
177 |
167 |
|
168 bool QSoftKeyManager::appendSoftkeys(const QWidget &source, int level) |
|
169 { |
|
170 Q_D(QSoftKeyManager); |
|
171 bool ret = false; |
|
172 QList<QAction*> actions = source.actions(); |
|
173 for (int i = 0; i < actions.count(); ++i) { |
|
174 if (actions.at(i)->softKeyRole() != QAction::NoSoftKey) { |
|
175 d->requestedSoftKeyActions.insert(level, actions.at(i)); |
|
176 ret = true; |
|
177 } |
|
178 } |
|
179 return ret; |
|
180 } |
|
181 |
|
182 QWidget *QSoftKeyManager::softkeySource(QWidget *previousSource, bool& recursiveMerging) |
|
183 { |
|
184 Q_D(QSoftKeyManager); |
|
185 QWidget *source = NULL; |
|
186 if (!previousSource) { |
|
187 // Initial source is primarily focuswidget and secondarily activeWindow |
|
188 source = QApplication::focusWidget(); |
|
189 if (!source) |
|
190 source = QApplication::activeWindow(); |
|
191 } else { |
|
192 // Softkey merging is based on four criterias |
|
193 // 1. Implicit merging is used whenever focus widget does not specify any softkeys |
|
194 bool implicitMerging = d->requestedSoftKeyActions.isEmpty(); |
|
195 // 2. Explicit merging with parent is used whenever WA_MergeSoftkeys widget attribute is set |
|
196 bool explicitMerging = previousSource->testAttribute(Qt::WA_MergeSoftkeys); |
|
197 // 3. Explicit merging with all parents |
|
198 recursiveMerging |= previousSource->testAttribute(Qt::WA_MergeSoftkeysRecursively); |
|
199 // 4. Implicit and explicit merging always stops at window boundary |
|
200 bool merging = (implicitMerging || explicitMerging || recursiveMerging) && !previousSource->isWindow(); |
|
201 |
|
202 source = merging ? previousSource->parentWidget() : NULL; |
|
203 } |
|
204 return source; |
|
205 } |
|
206 |
|
207 bool QSoftKeyManager::handleUpdateSoftKeys() |
|
208 { |
|
209 Q_D(QSoftKeyManager); |
|
210 int level = 0; |
|
211 d->requestedSoftKeyActions.clear(); |
|
212 bool recursiveMerging = false; |
|
213 QWidget *source = softkeySource(NULL, recursiveMerging); |
|
214 do { |
|
215 if (source) { |
|
216 bool added = appendSoftkeys(*source, level); |
|
217 source = softkeySource(source, recursiveMerging); |
|
218 level = added ? ++level : level; |
|
219 } |
|
220 } while (source); |
|
221 |
|
222 d->updateSoftKeys_sys(); |
|
223 return true; |
|
224 } |
|
225 |
178 bool QSoftKeyManager::event(QEvent *e) |
226 bool QSoftKeyManager::event(QEvent *e) |
179 { |
227 { |
180 #ifndef QT_NO_ACTION |
228 #ifndef QT_NO_ACTION |
181 if (e->type() == QEvent::UpdateSoftKeys) { |
229 if (e->type() == QEvent::UpdateSoftKeys) |
182 QList<QAction*> softKeys; |
230 return handleUpdateSoftKeys(); |
183 QWidget *source = QApplication::focusWidget(); |
|
184 do { |
|
185 if (source) { |
|
186 QList<QAction*> actions = source->actions(); |
|
187 for (int i = 0; i < actions.count(); ++i) { |
|
188 if (actions.at(i)->softKeyRole() != QAction::NoSoftKey) |
|
189 softKeys.append(actions.at(i)); |
|
190 } |
|
191 |
|
192 QWidget *parent = source->parentWidget(); |
|
193 if (parent && softKeys.isEmpty() && !source->isWindow()) |
|
194 source = parent; |
|
195 else |
|
196 break; |
|
197 } else { |
|
198 source = QApplication::activeWindow(); |
|
199 } |
|
200 } while (source); |
|
201 |
|
202 QSoftKeyManagerPrivate::softKeySource = source; |
|
203 QSoftKeyManagerPrivate::updateSoftKeys_sys(softKeys); |
|
204 return true; |
|
205 } |
|
206 #endif //QT_NO_ACTION |
231 #endif //QT_NO_ACTION |
207 return false; |
232 return false; |
208 } |
233 } |
209 |
234 |
210 #ifdef Q_WS_S60 |
235 #ifdef Q_WS_S60 |
211 void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys) |
|
212 { |
|
213 // lets not update softkeys if s60 native dialog or menu is shown |
|
214 if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) |
|
215 || CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog()) |
|
216 return; |
|
217 |
|
218 CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); |
|
219 nativeContainer->DrawableWindow()->SetOrdinalPosition(0); |
|
220 nativeContainer->DrawableWindow()->SetPointerCapturePriority(1); //keep softkeys available in modal dialog |
|
221 nativeContainer->DrawableWindow()->SetFaded(EFalse, RWindowTreeNode::EFadeIncludeChildren); |
|
222 |
|
223 int position = -1; |
|
224 bool needsExitButton = true; |
|
225 QT_TRAP_THROWING( |
|
226 //Using -1 instead of EAknSoftkeyEmpty to avoid flickering. |
|
227 nativeContainer->SetCommandL(0, -1, KNullDesC); |
|
228 nativeContainer->SetCommandL(2, -1, KNullDesC); |
|
229 ); |
|
230 |
|
231 for (int index = 0; index < softkeys.count(); index++) { |
|
232 const QAction* softKeyAction = softkeys.at(index); |
|
233 switch (softKeyAction->softKeyRole()) { |
|
234 // Positive Actions on the LSK |
|
235 case QAction::PositiveSoftKey: |
|
236 position = 0; |
|
237 break; |
|
238 case QAction::SelectSoftKey: |
|
239 position = 0; |
|
240 break; |
|
241 // Negative Actions on the RSK |
|
242 case QAction::NegativeSoftKey: |
|
243 needsExitButton = false; |
|
244 position = 2; |
|
245 break; |
|
246 default: |
|
247 break; |
|
248 } |
|
249 |
|
250 int command = (softKeyAction->objectName().contains(QLatin1String("_q_menuSoftKeyAction"))) |
|
251 ? EAknSoftkeyOptions |
|
252 : s60CommandStart + index; |
|
253 |
|
254 // _q_menuSoftKeyAction action is set to "invisible" and all invisible actions are by default |
|
255 // disabled. However we never want to dim options softkey, even it is set to "invisible" |
|
256 bool dimmed = (command == EAknSoftkeyOptions) ? false : !softKeyAction->isEnabled(); |
|
257 |
|
258 if (position != -1) { |
|
259 const int underlineShortCut = QApplication::style()->styleHint(QStyle::SH_UnderlineShortcut); |
|
260 QString iconText = softKeyAction->iconText(); |
|
261 TPtrC text = qt_QString2TPtrC( underlineShortCut ? softKeyAction->text() : iconText); |
|
262 QT_TRAP_THROWING( |
|
263 nativeContainer->SetCommandL(position, command, text); |
|
264 nativeContainer->DimCommand(command, dimmed); |
|
265 ); |
|
266 } |
|
267 } |
|
268 |
|
269 const Qt::WindowType sourceWindowType = QSoftKeyManagerPrivate::softKeySource |
|
270 ? QSoftKeyManagerPrivate::softKeySource->window()->windowType() |
|
271 : Qt::Widget; |
|
272 |
|
273 if (needsExitButton && sourceWindowType != Qt::Dialog && sourceWindowType != Qt::Popup) |
|
274 QT_TRAP_THROWING( |
|
275 nativeContainer->SetCommandL(2, EAknSoftkeyExit, qt_QString2TPtrC(QSoftKeyManager::tr("Exit")))); |
|
276 |
|
277 nativeContainer->DrawDeferred(); // 3.1 needs an extra invitation |
|
278 } |
|
279 |
|
280 bool QSoftKeyManager::handleCommand(int command) |
236 bool QSoftKeyManager::handleCommand(int command) |
281 { |
237 { |
282 if (command >= s60CommandStart && QSoftKeyManagerPrivate::softKeySource) { |
238 return static_cast<QSoftKeyManagerPrivateS60*>(QSoftKeyManager::instance()->d_func())->handleCommand(command); |
283 int index = command - s60CommandStart; |
239 } |
284 const QList<QAction*>& softKeys = QSoftKeyManagerPrivate::softKeySource->actions(); |
|
285 for (int i = 0, j = 0; i < softKeys.count(); ++i) { |
|
286 QAction *action = softKeys.at(i); |
|
287 if (action->softKeyRole() != QAction::NoSoftKey) { |
|
288 if (j == index) { |
|
289 QWidget *parent = action->parentWidget(); |
|
290 if (parent && parent->isEnabled()) { |
|
291 action->activate(QAction::Trigger); |
|
292 return true; |
|
293 } |
|
294 } |
|
295 j++; |
|
296 } |
|
297 } |
|
298 } |
|
299 |
|
300 return false; |
|
301 } |
|
302 |
|
303 #else |
|
304 |
|
305 void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &) |
|
306 { |
|
307 } |
|
308 |
|
309 #endif |
240 #endif |
310 |
241 |
311 QT_END_NAMESPACE |
242 QT_END_NAMESPACE |
312 #endif //QT_NO_SOFTKEYMANAGER |
243 #endif //QT_NO_SOFTKEYMANAGER |