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