src/gui/kernel/qsoftkeymanager.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtGui module of the Qt Toolkit.
     7 ** This file is part of the QtGui module of the Qt Toolkit.
     8 **
     8 **
    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 
   145     QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key);
   136     QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key);
   146     return action.take();
   137     return action.take();
   147 #endif //QT_NO_ACTION
   138 #endif //QT_NO_ACTION
   148 }
   139 }
   149 
   140 
   150 void QSoftKeyManager::cleanupHash(QObject* obj)
   141 void QSoftKeyManager::cleanupHash(QObject *obj)
   151 {
   142 {
   152     Q_D(QSoftKeyManager);
   143     Q_D(QSoftKeyManager);
   153     QAction *action = qobject_cast<QAction*>(obj);
   144     QAction *action = qobject_cast<QAction*>(obj);
   154     d->keyedActions.remove(action);
   145     d->keyedActions.remove(action);
   155 }
   146 }
   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