src/gui/kernel/qsoftkeymanager.cpp
branchRCL_3
changeset 5 d3bac044e0f0
parent 4 3b1da2848fc7
child 7 3f74d0d4af4c
equal deleted inserted replaced
4:3b1da2848fc7 5:d3bac044e0f0
    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;
   145     QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key);
   135     QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key);
   146     return action.take();
   136     return action.take();
   147 #endif //QT_NO_ACTION
   137 #endif //QT_NO_ACTION
   148 }
   138 }
   149 
   139 
   150 void QSoftKeyManager::cleanupHash(QObject* obj)
   140 void QSoftKeyManager::cleanupHash(QObject *obj)
   151 {
   141 {
   152     Q_D(QSoftKeyManager);
   142     Q_D(QSoftKeyManager);
   153     QAction *action = qobject_cast<QAction*>(obj);
   143     QAction *action = qobject_cast<QAction*>(obj);
   154     d->keyedActions.remove(action);
   144     d->keyedActions.remove(action);
   155 }
   145 }
   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