Ticket #590: mythcontrols-usedkeys3.patch

File mythcontrols-usedkeys3.patch, 39.8 KB (added by mythtv@…, 18 years ago)

fixed per comments in Ticket

  • mythcontrols.cpp

     
    4646#include "keygrabber.h"
    4747
    4848
     49static QMap<int,QString> FindContexts(const QString &context)
     50{
     51    QMap<int,QString> retval;
     52    retval.clear();
     53    if (context != JUMP_CONTEXT) retval[-1] = JUMP_CONTEXT;
     54    retval[0] = context;
     55    if (context != JUMP_CONTEXT && context != GLOBAL_CONTEXT)
     56    {
     57        if (context == "TV Editting")
     58            retval[1] = "TV Playback";
     59        retval[2] = GLOBAL_CONTEXT;
     60        if (context != "qt")
     61            retval[3] = "qt";
     62    }
     63    return retval;
     64}
    4965
     66static const QString KeyToDisplay(const QString key)
     67{
     68    if (key.left(6) == "remote")
     69        return "[" + key.mid(6) + "]";
     70    else
     71        return key;
     72}
     73
     74static const QString DisplayToKey(const QString key)
     75{
     76    if (key.left(1) == "[" && key != "[")
     77        return "remote" + key.mid(1,key.length()-2);
     78    else
     79        return key;
     80}
     81
    5082/* comments in header */
    5183MythControls::MythControls (MythMainWindow *parent, bool& ui_ok)
    5284    :MythThemedDialog(parent, "controls", "controls-", "controls")
     
    6092    /* load up the ui components */
    6193    if ((ui_ok = loadUI()))
    6294    {
     95        leftType = kContextList;
     96        rightType = kActionList;
     97
    6398        /* for starters, load this host */
    6499        loadHost(gContext->GetHostName());
    65100
     
    67102        refreshKeyInformation();
    68103
    69104        /* capture the signals we want */
    70         connect(ContextList, SIGNAL(itemSelected(UIListBtnTypeItem*)),
    71                 this, SLOT(contextSelected(UIListBtnTypeItem*)));
    72         connect(ActionList, SIGNAL(itemSelected(UIListBtnTypeItem*)),
    73                 this, SLOT(actionSelected(UIListBtnTypeItem*)));
     105        connect(LeftList, SIGNAL(itemSelected(UIListBtnTypeItem*)),
     106                this, SLOT(leftSelected(UIListBtnTypeItem*)));
     107        connect(RightList, SIGNAL(itemSelected(UIListBtnTypeItem*)),
     108                this, SLOT(rightSelected(UIListBtnTypeItem*)));
    74109
    75110    }
    76111}
     
    99134        VERBOSE(VB_ALL, "MythControls:  No controls container in theme");
    100135        retval = false;
    101136    }
    102     else if ((ContextList = getUIListBtnType("contextlist")) == NULL) {
    103         VERBOSE(VB_ALL, "MythControls:  No context_list in theme");
     137    else if ((LeftList = getUIListBtnType("leftlist")) == NULL) {
     138        VERBOSE(VB_ALL, "MythControls:  No leftlist in theme");
    104139        retval = false;
    105140    }
    106     else if ((ActionList = getUIListBtnType("actionlist")) == NULL) {
    107         VERBOSE(VB_ALL, "MythControls:  No ActionList in theme");
     141    else if ((RightList = getUIListBtnType("rightlist")) == NULL) {
     142        VERBOSE(VB_ALL, "MythControls:  No rightList in theme");
    108143        retval = false;
    109144    }
    110145    else {
     146        LeftDesc = getUITextType("leftdesc");
     147        RightDesc = getUITextType("rightdesc");
    111148        /* focus the context list by default */
    112         focused = ContextList;
    113         ContextList->calculateScreenArea();
    114         ContextList->SetActive(true);
    115         ActionList->calculateScreenArea();
    116         ActionList->SetActive(false);
     149        focused = LeftList;
     150        LeftList->calculateScreenArea();
     151        LeftList->SetActive(true);
     152        RightList->calculateScreenArea();
     153        RightList->SetActive(false);
    117154    }
    118155
    119156    /* Check that all the buttons are there */
     
    155192
    156193void MythControls::focusButton(int direction)
    157194{
     195    if (leftType != kContextList || rightType != kActionList)
     196        return;
    158197    if (direction == 0)
    159198    {
    160199        focused = ActionButtons[0];
    161200        ActionButtons[0]->takeFocus();
    162         ActionList->looseFocus();
    163         ActionList->SetActive(false);
     201        RightList->looseFocus();
     202        RightList->SetActive(false);
    164203    }
    165204    else
    166205    {
     
    203242    refreshKeyInformation();
    204243}
    205244
    206 
    207 
    208245void MythControls::keyPressEvent(QKeyEvent *e)
    209246{
    210247    bool handled = false;
     248    bool escape = false;
    211249    QStringList actions;
    212250    gContext->GetMainWindow()->TranslateKeyPress("Controls", e, actions);
    213251
     
    218256
    219257        if (action == "MENU" || action == "INFO")
    220258        {
     259            focused->looseFocus();
    221260            OptionsMenu popup(gContext->GetMainWindow());
    222             if (popup.getOption() == OptionsMenu::SAVE) save();
     261            int a = (int)popup.getOption();
     262            switch (a) {
     263                case (int)OptionsMenu::SAVE:
     264                    save();
     265                    break;
     266            }
     267            focused->takeFocus();
     268//            if (popup.getOption() == OptionsMenu::SAVE) save();
    223269        }
    224270        else if (action == "SELECT")
    225271        {
    226             if (focused == ContextList)
    227                 switchListFocus(ActionList, ContextList);
    228             else if (focused == ActionList)
     272            if (focused == LeftList)
     273                switchListFocus(RightList, LeftList);
     274            else if (focused == RightList)
    229275                focusButton(0);
    230276            else {
    231                 ActionMenu popup(gContext->GetMainWindow());
    232                 int result = popup.getOption();
    233                 if (result == ActionMenu::SET) addKeyToAction();
    234                 else if (result == ActionMenu::REMOVE) deleteKey();
     277                QString key = getCurrentKey();
     278                if (!key.isEmpty())
     279                {
     280                    ActionMenu popup(gContext->GetMainWindow());
     281                    int result = popup.getOption();
     282                    if (result == ActionMenu::SET) addKeyToAction();
     283                    else if (result == ActionMenu::REMOVE) deleteKey();
     284                } else // for blank keys, no reason to ask what to do
     285                    addKeyToAction();
    235286            }
    236287        }
    237288        else if (action == "ESCAPE")
    238289        {
    239             if (focused == ContextList)
     290            escape = true;
     291            if (focused == LeftList)
    240292            {
    241293                handled = false;
    242294                if (key_bindings->hasChanges())
     
    249301                    }
    250302                }
    251303            }
    252             else if (focused == ActionList)
    253                 switchListFocus(ContextList, ActionList);
     304            else if (focused == RightList)
     305                switchListFocus(LeftList, RightList);
    254306            else
    255                 switchListFocus(ActionList, NULL);
     307                switchListFocus(RightList, NULL);
    256308        }
    257309        else if (action == "UP")
    258310        {
    259             if (focused == ContextList)
    260                 ContextList->MoveUp();
    261             else if (focused == ActionList)
    262                 ActionList->MoveUp();
     311            if (focused == LeftList)
     312                LeftList->MoveUp();
     313            else if (focused == RightList)
     314                RightList->MoveUp();
    263315        }
    264316        else if (action == "DOWN")
    265317        {
    266             if (focused == ContextList)
    267                 ContextList->MoveDown();
    268             else if (focused == ActionList)
    269                 ActionList->MoveDown();
     318            if (focused == LeftList)
     319                LeftList->MoveDown();
     320            else if (focused == RightList)
     321                RightList->MoveDown();
    270322        }
    271323        else if (action == "LEFT")
    272324        {
    273             if (focused==ActionList)
    274                 switchListFocus(ContextList, ActionList);
    275             else if (focused != ContextList)
     325            if (focused==RightList)
     326                switchListFocus(LeftList, RightList);
     327            else if (focused != LeftList)
    276328                focusButton(-1);
    277329        }
    278330        else if (action == "RIGHT")
    279331        {
    280             if (focused == ContextList)
    281                 switchListFocus(ActionList, ContextList);
    282             else if (focused != ActionList)
     332            if (focused == LeftList)
     333                switchListFocus(RightList, LeftList);
     334            else if (focused != RightList)
    283335                focusButton(1);
    284336        }
    285337        else if (action == "PAGEUP")
    286338        {
    287             if (focused == ContextList)
    288                 ContextList->MoveUp(UIListBtnType::MovePage);
    289             else if (focused == ActionList)
    290                 ActionList->MoveUp(UIListBtnType::MovePage);
     339            if (focused == LeftList)
     340                LeftList->MoveUp(UIListBtnType::MovePage);
     341            else if (focused == RightList)
     342                RightList->MoveUp(UIListBtnType::MovePage);
    291343        }
    292344        else if (action == "PAGEDOWN")
    293345        {
    294             if (focused == ContextList)
    295                 ContextList->MoveDown(UIListBtnType::MovePage);
    296             else if (focused == ActionList)
    297                 ActionList->MoveDown(UIListBtnType::MovePage);
     346            if (focused == LeftList)
     347                LeftList->MoveDown(UIListBtnType::MovePage);
     348            else if (focused == RightList)
     349                RightList->MoveDown(UIListBtnType::MovePage);
    298350        }
     351        else if (action == "1")
     352        {
     353            if (leftType != kContextList || rightType != kActionList)
     354            {
     355                leftType = kContextList;
     356                rightType = kActionList;
     357                updateLists();
     358                if (focused != LeftList)
     359                    switchListFocus(LeftList,
     360                                    (focused == RightList) ? RightList : NULL);
     361            } else handled = false;
     362        }
     363        else if (action == "2")
     364        {
     365            if (leftType != kContextList || rightType != kKeyList)
     366            {
     367                leftType = kContextList;
     368                rightType = kKeyList;
     369                updateLists();
     370                if (focused != LeftList)
     371                    switchListFocus(LeftList,
     372                                    (focused == RightList) ? RightList : NULL);
     373            } else handled = false;
     374        }
     375        else if (action == "3")
     376        {
     377            if (leftType != kKeyList || rightType != kContextList)
     378            {
     379                leftType = kKeyList;
     380                rightType = kContextList;
     381                updateLists();
     382                if (focused != LeftList)
     383                    switchListFocus(LeftList,
     384                                    (focused == RightList) ? RightList : NULL);
     385            } else handled = false;
     386        }
    299387        else handled = false;
    300388    }
    301389
     390    if (handled) return;
     391
     392    if (!escape && JumpTo(e)) handled = true;
     393
    302394    if (!handled)
    303395        MythThemedDialog::keyPressEvent(e);
    304396}
    305397
    306 void MythControls::contextSelected(UIListBtnTypeItem *item)
     398bool MythControls::JumpTo(QKeyEvent *e)
    307399{
    308     ContextList->refresh();
     400    UIListBtnType *list = NULL;
     401    if (focused == LeftList && leftType == kKeyList) list = LeftList;
     402    if (focused == RightList && rightType == kKeyList) list = RightList;
     403    if (!list) return false;
    309404
    310     ActionList->blockSignals(true);
    311     refreshActionList(getCurrentContext());
    312     ActionList->blockSignals(false);
     405    QString key = e->text();
     406    if (key.left(6) == "remote") {
     407        key = KeyToDisplay(key);
     408    } else {
     409        key = QString(QKeySequence(e->key()));
     410        if (key.isEmpty()) return false;
     411        QString modifiers = "";
     412        if (e->state()&Qt::ShiftButton) modifiers+="Shift+";
     413        if (e->state()&Qt::ControlButton) modifiers+="Ctrl+";
     414        if (e->state()&Qt::AltButton) modifiers+="Alt+";
     415        if (e->state()&Qt::MetaButton) modifiers+="Meta+";
     416        key = modifiers + key;
     417    }
    313418
    314     ActionList->refresh();
     419    UIListBtnTypeItem *b;
     420    uint len = 1024; // infinity
     421    if (list == RightList)
     422    {
     423        key = key + " ";
     424        len = key.length();
     425    }
     426
     427    for (b = list->GetItemFirst(); b; b = list->GetItemNext(b))
     428        if (b->text().left(len) == key) break;
     429    if (!b) return false;
     430
     431    int curpos = list->GetItemPos(list->GetItemCurrent());
     432    int newpos = list->GetItemPos(b);
     433
     434    if (newpos > curpos)
     435        list->MoveDown(newpos - curpos);
     436    else if (newpos < curpos)
     437        list->MoveUp(curpos - newpos);
     438    return true;
    315439}
    316440
    317 void MythControls::actionSelected(UIListBtnTypeItem *item)
     441
     442void MythControls::leftSelected(UIListBtnTypeItem*)
    318443{
    319     ContextList->refresh();
     444    LeftList->refresh();
     445    RightList->blockSignals(true);
     446    refreshRightList();
     447    RightList->blockSignals(false);
     448    RightList->refresh();
     449}
     450
     451void MythControls::rightSelected(UIListBtnTypeItem*)
     452{
     453    RightList->refresh();
    320454    refreshKeyInformation();
    321455}
    322456
    323457
    324458
    325459/* method description in header */
    326 void MythControls::refreshActionList(const QString & context)
     460void MythControls::refreshRightList()
    327461{
    328     ActionList->Reset();
     462    RightList->Reset();
    329463
    330     /* add all of the actions to the context list */
    331     QStringList *actions = m_contexts[getCurrentContext()];
    332     UIListBtnTypeItem *item;
    333     for (size_t i = 0; i < actions->size(); i++)
    334         item = new UIListBtnTypeItem(ActionList, (*actions)[i]);
     464    if (LeftList->GetItemCurrent() == NULL)
     465        return;
     466
     467    if (leftType == kContextList)
     468    {
     469        if (rightType == kActionList)
     470        {
     471            /* add all of the actions to the context list */
     472            QString context = LeftList->GetItemCurrent()->text();
     473            QStringList *actions = m_contexts[context];
     474            if (actions == NULL)
     475            {
     476                VERBOSE(VB_ALL, QString("MythControls: Unable to find actions for context %1").arg(context));
     477                return;
     478            }
     479            UIListBtnTypeItem *item;
     480            for (size_t i = 0; i < actions->size(); i++)
     481                item = new UIListBtnTypeItem(RightList, (*actions)[i]);
     482        }
     483        else if (rightType == kKeyList)
     484        {
     485            /* add all of the actions to the context list */
     486            QString context = LeftList->GetItemCurrent()->text();
     487            BindingList *list = contextKeys[context];
     488            if (list == NULL)
     489            {
     490                VERBOSE(VB_ALL, QString("MythControls: Unable to find keys for context %1").arg(context));
     491                return;
     492            }
     493            UIListBtnTypeItem *item;
     494            for (BindingList::iterator it = list->begin(); it != list->end(); ++it)
     495            {
     496                binding_t *b = *it;
     497                item = new UIListBtnTypeItem(RightList, KeyToDisplay(b->key) + " => " + b->action);
     498            }
     499        }
     500    } else if (leftType == kKeyList && rightType == kContextList)
     501    {
     502        QString key = DisplayToKey(LeftList->GetItemCurrent()->text());
     503        BindingList *list = keyActions[key];
     504        if (list == NULL)
     505        {
     506            VERBOSE(VB_ALL, QString("MythControls: Unable to find actions for key %1").arg(key));
     507            return;
     508        }
     509        UIListBtnTypeItem *item;
     510        BindingList::iterator it = list->begin();
     511        binding_t *b = *it;
     512        for (size_t i = 0; i < contexts.size(); i++)
     513        {
     514            QString context = contexts[i];
     515            QString action = "<none>";
     516            if (b && b->context == context)
     517            {
     518                action = b->action;
     519                ++it;
     520                if (it != list->end()) b = *it;
     521                else b = NULL;
     522            }
     523            item = new UIListBtnTypeItem(RightList, context + " => " + action);
     524        }
     525    }
    335526}
    336527
    337528
    338 
    339529/* comments in header */
    340530void MythControls::refreshKeyInformation()
    341531{
    342532    /* get the description of the current action */
    343533    QString desc;
    344534
    345     if (focused == ContextList)
     535    if (focused == LeftList)
    346536    {
    347537        /* blank all keys on the context */
    348538        for (size_t i = 0; i < Action::MAX_KEYS; i++)
    349539            ActionButtons[i]->setText("");
    350540    }
    351     else
    352     {
     541    else if (leftType == kKeyList || rightType == kKeyList)
     542    { // Should show appropriate description
     543        QString action = getCurrentAction();
     544        QString context = getCurrentContext();
     545        /* blank all keys on the context */
     546        for (size_t i = 0; i < Action::MAX_KEYS; i++)
     547            ActionButtons[i]->setText("");
     548        if (!action.isEmpty())
     549            {
     550   
     551            desc = key_bindings->getActionDescription(context, action);
     552   
     553            BindingList *list = NULL;
     554            if (leftType == kKeyList && rightType == kContextList)
     555            {
     556                QString key = getCurrentKey();
     557                list = keyActions[DisplayToKey(key)];
     558            }
     559            else if (leftType == kContextList && rightType == kKeyList)
     560                list = contextKeys[context];
     561            if (list)
     562            {
     563                QString searchKey;
     564                if (rightType == kContextList)
     565                    searchKey = context;
     566                else if (rightType == kActionList)
     567                    searchKey = action;
     568                else if (rightType == kKeyList)
     569                    searchKey = DisplayToKey(getCurrentKey());
     570                binding_t *binding = NULL;
     571                for (BindingList::iterator it = list->begin(); it != list->end(); ++it)
     572                {
     573                    binding_t *b = *it;
     574                    switch (rightType)
     575                    {
     576                        case kContextList:
     577                            if (b->context == searchKey) binding = b;
     578                            break;
     579                        case kActionList:
     580                            if (b->action == searchKey) binding = b;
     581                            break;
     582                        case kKeyList:
     583                            if (b->key == searchKey) binding = b;
     584                            break;
     585                    }
     586                    if (binding) break;
     587                }
     588   
     589                if (binding)
     590                {
     591                    if (desc.isEmpty() && context != binding->contextFrom)
     592                        desc = key_bindings->getActionDescription(binding->contextFrom, action);
     593                    desc += "\n" + tr("Binding comes from %1 context")
     594                            .arg(binding->contextFrom);
     595                }
     596            }
     597        }
     598    } else {
     599        QString context = getCurrentContext();
     600        QString action = getCurrentAction();
    353601        /* set the description */
    354602        desc = key_bindings->getActionDescription(getCurrentContext(),
    355603                                                  getCurrentAction());
     
    362610
    363611        /* fill existing keys */
    364612        for (i = 0; i < keys.count(); i++)
    365             ActionButtons[i]->setText(keys[i]);
     613            ActionButtons[i]->setText(KeyToDisplay(keys[i]));
    366614
    367615        /* blank the other ones */
    368616        for (; i < Action::MAX_KEYS; i++)
     
    378626/* comments in header */
    379627QString MythControls::getCurrentContext(void) const
    380628{
    381     return ContextList->GetItemCurrent()->text();
     629    if (leftType == kContextList)
     630        return LeftList->GetItemCurrent()->text();
     631    if (focused == LeftList) return "";
     632
     633    QString desc = RightList->GetItemCurrent()->text();
     634    int loc = desc.find(" => ");
     635    if (loc == -1) return ""; // Should not happen
     636    if (rightType == kContextList) return desc.left(loc);
     637    else return desc.mid(loc+4);
    382638}
    383639
     640/* comments in header */
     641QString MythControls::getCurrentAction(void) const
     642{
     643    if (leftType == kActionList)
     644        return LeftList->GetItemCurrent()->text();
     645    if (focused == LeftList) return "";
    384646
     647    QString desc = RightList->GetItemCurrent()->text();
     648    if (leftType == kContextList && rightType == kActionList)
     649        return desc;
     650    int loc = desc.find(" => ");
     651    if (loc == -1) return ""; // Should not happen
     652    if (rightType == kActionList) return desc.left(loc);
     653    else
     654    {
     655        QString rv = desc.mid(loc+4);
     656        if (rv == "<none>") return "";
     657        else return rv;
     658    }
     659}
    385660
    386661/* comments in header */
    387 QString MythControls::getCurrentAction(void) const
     662QString MythControls::getCurrentKey(void) const
    388663{
    389     return (focused != ContextList) ? ActionList->GetItemCurrent()->text() : "";
     664    if (leftType == kKeyList)
     665        return LeftList->GetItemCurrent()->text();
     666    if (focused == LeftList) return "";
     667
     668    if (leftType == kContextList && rightType == kActionList)
     669    {
     670        QString context = getCurrentContext();
     671        QString action = getCurrentAction();
     672        size_t b = focusedButton();
     673        QStringList keys = key_bindings->getActionKeys(context, action);
     674        if (b < keys.count()) return keys[b];
     675        else return "";
     676    }
     677
     678    QString desc = RightList->GetItemCurrent()->text();
     679    int loc = desc.find(" => ");
     680    if (loc == -1) return ""; // Should not happen
     681    if (rightType == kKeyList) return desc.left(loc);
     682    else return desc.mid(loc+4);
    390683}
    391684
    392685
    393 
    394686/* comments in header */
    395687void MythControls::loadHost(const QString & hostname) {
    396688
    397689    /* create the key bindings and the tree */
    398690    key_bindings = new KeyBindings(hostname);
    399     QStringList * context_names = key_bindings->getContexts();
     691    contexts = *key_bindings->getContexts();
    400692
     693    keys.clear();
     694
    401695    /* Alphabetic order, but jump and global at the top  */
    402     context_names->sort();
    403     context_names->remove(JUMP_CONTEXT);
    404     context_names->remove(GLOBAL_CONTEXT);
    405     context_names->insert(context_names->begin(), 1, GLOBAL_CONTEXT);
    406     context_names->insert(context_names->begin(), 1, JUMP_CONTEXT);
     696    contexts.sort();
     697    contexts.remove(JUMP_CONTEXT);
     698    contexts.remove(GLOBAL_CONTEXT);
     699    contexts.insert(contexts.begin(), 1, GLOBAL_CONTEXT);
     700    contexts.insert(contexts.begin(), 1, JUMP_CONTEXT);
    407701
    408     UIListBtnTypeItem *item;
    409702    QStringList *actions;
    410     for (size_t i = 0; i < context_names->size(); i++)
     703    for (size_t i = 0; i < contexts.size(); i++)
    411704    {
    412         item = new UIListBtnTypeItem(ContextList, (*context_names)[i]);
    413         item->setDrawArrow(true);
    414         actions = key_bindings->getActions((*context_names)[i]);
     705        actions = key_bindings->getActions(contexts[i]);
    415706        actions->sort();
    416         m_contexts.insert((*context_names)[i], actions);
     707        m_contexts.insert(contexts[i], actions);
    417708    }
    418709
    419     refreshActionList((*context_names)[0]);
    420     free(context_names);
     710    refreshKeyBindings();
     711    updateLists();
    421712}
    422713
    423714
     
    425716/* comments in header */
    426717void MythControls::deleteKey()
    427718{
    428     size_t b = focusedButton();
    429     QString action = getCurrentAction(), context = getCurrentContext();
    430     QStringList keys = key_bindings->getActionKeys(context, action);
    431     if (b < keys.count())
     719    // This code needs work to support deleteKey in any mode exc. Context/Action
     720    QString context = getCurrentContext();
     721    QString key = getCurrentKey();
     722    QString action = getCurrentAction();
     723    if (context.isEmpty() || key.isEmpty() || action.isEmpty())
    432724    {
    433         if (!key_bindings->removeActionKey(context, action, keys[b]))
    434         {
    435             InvalidBindingPopup popup(gContext->GetMainWindow());
    436             popup.getOption();
    437         }
    438         else refreshKeyInformation();
     725        InvalidBindingPopup popup(gContext->GetMainWindow());
     726        popup.getOption();
     727        return;
    439728    }
    440 }
    441729
     730    BindingList *list = keyActions[key];
     731    binding_t *binding = NULL;
     732    for (BindingList::iterator it = list->begin(); it != list->end(); ++it)
     733    {
     734        binding_t *b = *it;
     735        if (b->context == context) binding = b;
     736    }
     737    if (!binding)
     738    {
     739        InvalidBindingPopup popup(gContext->GetMainWindow());
     740        popup.getOption();
     741        return;
     742    }
    442743
     744    if (binding->contextFrom != context)
     745    {
     746        ConfirmMenu popup(gContext->GetMainWindow(), tr("Delete this key binding from context %1?").arg(binding->contextFrom));
     747        if (popup.getOption() != ConfirmMenu::CONFIRM) return;
     748    } else {
     749        ConfirmMenu popup(gContext->GetMainWindow(), tr("Delete this binding?"));
     750        if (popup.getOption() != ConfirmMenu::CONFIRM) return;
     751    }
    443752
     753    if (!key_bindings->removeActionKey(binding->contextFrom, action, key))
     754    {
     755        InvalidBindingPopup popup(gContext->GetMainWindow());
     756        popup.getOption();
     757        return;
     758    }
     759
     760    // refreshing everything is overkill.  I tried incrementally updating, but the
     761    // code was ugly.  Since this is quick in my experience, overkill away!
     762    refreshKeyBindings();
     763    refreshKeyInformation();
     764}
     765
    444766/* method description in header */
    445767bool MythControls::resolveConflict(ActionID *conflict, int level)
    446768{
     
    475797/* method description in header */
    476798void MythControls::addKeyToAction(void)
    477799{
     800    // This code needs work to support deleteKey in any mode exc. Context/Action
    478801    /* grab a key from the user */
    479802    KeyGrabPopupBox *kg = new KeyGrabPopupBox(gContext->GetMainWindow());
    480803    int result = kg->ExecPopup(kg,SLOT(cancel()));
     
    511834    else
    512835        key_bindings->addActionKey(context, action, key);
    513836
     837    refreshKeyBindings();
    514838    refreshKeyInformation();
    515839}
    516840
     841void MythControls::addBindings(QDict<binding_t> &bindings, const QString &context, const QString &contextParent, int bindlevel)
     842{
     843    QStringList *actions = key_bindings->getActions(context);
     844
     845    for (size_t i = 0; i < actions->size(); i++)
     846    {
     847        QString action = (*actions)[i];
     848        QStringList keys = key_bindings->getActionKeys(context, action);
     849
     850        for (size_t j = 0; j < keys.size(); j++)
     851        {
     852            QString key = keys[j];
     853
     854            binding_t *b = bindings.find(key);
     855            if (!b)
     856            {
     857                b = new(binding_t);
     858                b->key = key;
     859                b->action = action;
     860                b->context = contextParent;
     861                b->contextFrom = context;
     862                b->bindlevel = bindlevel;
     863                bindings.insert(key, b);
     864            }
     865            else if (b->bindlevel == bindlevel)
     866            {
     867                b->action += ", " + action;
     868            }
     869        }
     870    }
     871}
     872
     873BindingList *MythControls::getKeyBindings(const QString &context)
     874{
     875    QDict<binding_t> bindings;
     876    bindings.clear();
     877
     878    QMap<int,QString> contextList = FindContexts(context);
     879    for (QMap<int,QString>::iterator it = contextList.begin(); it != contextList.end(); ++it)
     880    {
     881        int level = it.key();
     882        QString curcontext = it.data();
     883        addBindings(bindings, curcontext, context, level);
     884    }
     885
     886    QStringList keys;
     887
     888    for (QDictIterator<binding_t> it(bindings); it.current(); ++it)
     889    {
     890        QString key = it.currentKey();
     891        keys.append(key);
     892    }
     893
     894    sortKeyList(keys);
     895
     896    BindingList *retval = new BindingList;
     897    retval->clear();
     898
     899    for (QStringList::Iterator kit = keys.begin(); kit != keys.end(); ++kit)
     900    {
     901        QString key = *kit;
     902        retval->append(bindings[key]);
     903    }
     904    retval->setAutoDelete(true);
     905    return retval;
     906}
     907
     908void MythControls::refreshKeyBindings()
     909{
     910    contextKeys.clear();
     911    keyActions.clear();
     912    for (size_t i = 0; i < contexts.size(); i++)
     913    {
     914        QString context = contexts[i];
     915        BindingList *list = getKeyBindings(context);
     916        contextKeys.insert(context, list);
     917        for (BindingList::iterator it = list->begin(); it != list->end(); ++it)
     918        {
     919            binding_t *b = *it;
     920            BindingList *list = keyActions.find(b->key);
     921            if (!list)
     922            {
     923                list = new BindingList;
     924                list->clear();
     925                keyActions.insert(b->key, list);
     926            }
     927            keys.append(b->key);
     928            list->append(b);
     929        }
     930    }
     931    contextKeys.setAutoDelete(true);
     932    keyActions.setAutoDelete(true);
     933
     934    sortKeyList(keys);
     935}
     936
     937void MythControls::sortKeyList(QStringList &keys)
     938{
     939    QStringList t;
     940    t.clear();
     941
     942    for ( QStringList::Iterator it = keys.begin(); it != keys.end(); ++it )
     943    {
     944        QString key = *it;
     945
     946        QString keydesc = "3 ";
     947        if (key.left(6) == "remote")
     948        {
     949            keydesc = "0 ";
     950        }
     951        else if (key.length() == 1)
     952        {
     953            switch (key[0].category())
     954            {
     955                case QChar::Letter_Uppercase:
     956                    keydesc = "2 ";
     957                    break;
     958                case QChar::Number_DecimalDigit:
     959                    keydesc = "1 ";
     960                    break;
     961            }
     962        }
     963        else if (key.find("+", 1) != -1)
     964            keydesc = "4 ";
     965
     966        t.push_back(keydesc + key);
     967    }
     968    t.sort();
     969
     970    QString prev = "";
     971
     972    keys.clear();
     973    for (QStringList::Iterator kit = t.begin(); kit != t.end(); ++kit)
     974    {
     975        QString cur = (*kit).mid(2);
     976        if (cur != prev)
     977        {
     978            keys.append(cur);
     979            prev = cur;
     980        }
     981    }
     982}
     983
     984QString MythControls::getTypeDesc(ListType type)
     985{
     986    switch (type)
     987    {
     988        case kContextList:
     989            return tr("Contexts");
     990            break;
     991        case kKeyList:
     992            return tr("Keys");
     993            break;
     994        case kActionList:
     995            return tr("Actions");
     996            break;
     997        default:
     998            return "";
     999    }
     1000}
     1001
     1002void MythControls::updateLists()
     1003{
     1004    RightList->blockSignals(true);
     1005    LeftList->blockSignals(true);
     1006    LeftList->Reset();
     1007    if (leftType == kContextList)
     1008    {
     1009        UIListBtnTypeItem *item;
     1010        for (size_t i = 0; i < contexts.size(); i++)
     1011        {
     1012            item = new UIListBtnTypeItem(LeftList, contexts[i]);
     1013            item->setDrawArrow(true);
     1014        }
     1015    } else if (leftType == kKeyList)
     1016    {
     1017        UIListBtnTypeItem *item;
     1018        for (size_t i = 0; i < keys.size(); i++)
     1019        {
     1020            QString key = KeyToDisplay(keys[i]);
     1021            item = new UIListBtnTypeItem(LeftList, key);
     1022            item->setDrawArrow(true);
     1023        }
     1024    }
     1025    refreshRightList();
     1026    RightList->blockSignals(false);
     1027    LeftList->blockSignals(false);
     1028    LeftList->refresh();
     1029    RightList->refresh();
     1030
     1031    if (LeftDesc != NULL)
     1032        LeftDesc->SetText(getTypeDesc(leftType));
     1033    if (RightDesc != NULL)
     1034        RightDesc->SetText(getTypeDesc(rightType));
     1035}
     1036
     1037
    5171038#endif /* MYTHCONTROLS_CPP */
     1039
     1040/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythcontrols.h

     
    2929
    3030#include "keybindings.h"
    3131
     32typedef struct
     33{
     34    QString key;
     35    QString context;
     36    QString contextFrom;
     37    QString action;
     38    int bindlevel;
     39} binding_t;
    3240
     41typedef QPtrList<binding_t> BindingList;
     42
    3343/**
    3444 * @class MythControls
    3545 * @brief The myth controls configuration class.
     
    7181     */
    7282    QString getCurrentAction(void) const;
    7383
     84    /**
     85     * @brief Get the currently selected key string
     86     * @return The currently selected key string
     87     *
     88     * If no context is selected, an empty string is returned.
     89     */
     90    QString getCurrentKey(void) const;
     91
    7492   
    7593   
    7694protected:
     
    105123     * @param context The context, from which actions will be
    106124     * displayed.
    107125     */
    108     void refreshActionList(const QString & context);
     126    void refreshRightList(void);
    109127
    110128    /**
     129     * @brief Redisplay both the left and right lists and fix focus
     130     */
     131    void updateLists(void);
     132
     133    /**
    111134     * @brief Load the settings for a particular host.
    112135     * @param hostname The host to load settings for.
    113136     */
     
    143166     */
    144167    void switchListFocus(UIListBtnType *focus, UIListBtnType *unfocus);
    145168
     169    /**
     170     * @brief Add bindings to QDict<binding_t> for specified context
     171     * @param bindings the QDict to which to add the bindings
     172     * @param context the context to grab keybindings from
     173     * @param contextParent the context whose keybindings are being calculated
     174     * @param bindlevel the bind level associated with this context
     175     */
     176    void addBindings(QDict<binding_t> &bindings, const QString &context, const QString &contextParent, int bindlevel);
     177
     178    /**
     179     * @brief Create a BindingList for the specified context
     180     * @param context the context for which a BindingList should be created
     181     */
     182    BindingList *getKeyBindings(const QString &context);
     183
    146184private slots:
    147185
    148186/**
     
    161199    inline void save(void) { key_bindings->commitChanges(); }
    162200
    163201    /**
    164      * @brief Recieves a signal when an item in the context list is
     202     * @brief Recieves a signal when an item in the left list is
    165203     * selected.
    166204     * @param item The selected item.
    167205     */
    168     void contextSelected(UIListBtnTypeItem *item);
     206    void leftSelected(UIListBtnTypeItem *item);
    169207
    170208    /**
    171      * @brief Recieves a signal when an item in the action list is
     209     * @brief Recieves a signal when an item in the right list is
    172210     * selected.
    173211     * @param item The selected item.
    174212     */
    175     void actionSelected(UIListBtnTypeItem *item);
     213    void rightSelected(UIListBtnTypeItem *item);
    176214
     215    /**
     216     * @brief Sort a list of keys, removing duplicates
     217     * @param keys the list of keys to sort
     218     */
     219    void sortKeyList(QStringList &keys);
     220
     221    /**
     222     * @brief Refresh binding information
     223     */
     224    void refreshKeyBindings();
     225
     226    /**
     227     * @brief Jump to a particular key binding
     228     * @param e key event to use as jump
     229     */
     230    bool JumpTo(QKeyEvent *e);
     231
    177232private:
    178233
    179234    UIType *focused;
    180     UIListBtnType *ContextList;
    181     UIListBtnType *ActionList;
    182     UITextType *description;
     235    UIListBtnType *LeftList;
     236    UIListBtnType *RightList;
     237    UITextType *description, *LeftDesc, *RightDesc;
    183238    UITextButtonType * ActionButtons[Action::MAX_KEYS];
    184239    KeyBindings *key_bindings;
    185240    LayerSet *container;
    186     QDict<QStringList> m_contexts;
     241
     242    QStringList contexts; ///< sorted list of contexts
     243    QStringList keys; ///< sorted list of keys
     244
     245    QDict<QStringList> m_contexts; ///< actions for a given context
     246    QDict<BindingList> contextKeys; ///< key bindings for a given context
     247    QDict<BindingList> keyActions; ///< actions in each context for a given key
     248
     249    typedef enum { kContextList, kKeyList, kActionList } ListType;
     250    ListType leftType, rightType;
     251
     252    QString getTypeDesc(ListType type);
     253
    187254};
    188255
    189256
  • keybindings.h

     
    8484    }
    8585
    8686    /**
     87     * @brief Get a list of the actions in a context.
     88     * @param context The name of the context.
     89     * @return A list of action (names) for the target context.
     90     * @note Store this instead of calling repeatedly.  Every time you
     91     * do, ActionSet has to iterate over all contexts and actions.
     92     */
     93    inline void getKeyActions(const QString &key, ActionList &list) const
     94    {
     95        list = actionset.getActions(key);
     96    }
     97
     98    /**
    8799     * @brief Get an action's keys.
    88100     * @param context_name The name of the context.
    89101     * @param action_name The name of the action.
  • keygrabber.cpp

     
    153153    addButton(tr("Save"), this, SLOT(save()))->setFocus();
    154154    addButton(tr("Exit"), this, SLOT(cancel()));
    155155}
     156
     157ConfirmMenu::ConfirmMenu(MythMainWindow *window, QString msg)
     158    : MythPopupBox(window, "unsavedmenu")
     159{
     160    addLabel(tr("Confirm"), Large, false);
     161    addLabel(msg);
     162    addButton(tr("Confirm"), this, SLOT(confirm()))->setFocus();
     163    addButton(tr("Cancel"), this, SLOT(cancel()));
     164}
  • keygrabber.h

     
    141141
    142142public:
    143143
    144     enum actons { SAVE, CANCEL };
     144    enum actions { SAVE, CANCEL };
    145145
    146146    /**
    147147     * @brief Create a new action window.
     
    180180
    181181public:
    182182
    183     enum actons { SET, REMOVE, CANCEL };
     183    enum actions { SET, REMOVE, CANCEL };
    184184
    185185    /**
    186186     * @brief Create a new action window.
     
    222222
    223223public:
    224224
    225     enum actons { SAVE, EXIT };
     225    enum actions { SAVE, EXIT };
    226226
    227227    /**
    228228     * @brief Create a new action window.
     
    247247    inline void cancel(void) { done(UnsavedMenu::EXIT); }
    248248
    249249};
     250
     251/**
     252 * @class ConfirmMenu
     253 * @brief A popup confirming an action
     254 */
     255class ConfirmMenu : public MythPopupBox
     256{
     257
     258    Q_OBJECT;
     259
     260public:
     261
     262    enum actions { CONFIRM, CANCEL };
     263
     264    /**
     265     * @brief Create a new action window.
     266     */
     267    ConfirmMenu(MythMainWindow *window, QString msg);
     268
     269    /**
     270     * @brief Execute the option popup.
     271     */
     272    inline int getOption(void) { return ExecPopup(this,SLOT(cancel())); }
     273
     274public slots:
     275
     276    /**
     277     * @brief Slot to connect to when the save button is pressed.
     278     */
     279    inline void confirm(void) { done(UnsavedMenu::SAVE); }
     280
     281    /**
     282     * @brief Slot to connect to when the cancel button is pressed.
     283     */
     284    inline void cancel(void) { done(UnsavedMenu::EXIT); }
     285
     286};
  • controls-ui.xml

     
    2929   <bold>yes</bold>
    3030  </font>
    3131
     32  <font name="options" face="Arial">
     33   <color>#ffffff</color>
     34   <size>24</size>
     35   <bold>yes</bold>
     36  </font>
     37
     38
    3239  <font name="infotitle" face="Arial">
    3340   <color>#ffffff</color>
    34    <size>24</size>
     41   <size>20</size>
    3542   <shadow>10,10</shadow>
    3643   <bold>yes</bold>
    3744  </font>
    3845
    3946  <container name="controls">
    40    <area>20,20,780,380</area>
     47   <area>20,20,780,450</area>
    4148
    42    <listbtnarea name="contextlist" draworder="0">
    43     <area>0,0,370,360</area>
     49   <textarea name="options" draworder="1" align="center">
     50    <font>options</font>
     51    <area>0,0,780,30</area>
     52    <value>(1) Contexts / Actions  (2) Contexts / Keys  (3) Keys / Contexts</value>
     53   </textarea>
     54
     55   <textarea name="leftdesc" draworder="1" align="center">
     56    <font>info</font>
     57    <area>0,40,370,20</area>
     58    <value>Contexts</value>
     59   </textarea>
     60
     61   <listbtnarea name="leftlist" draworder="0">
     62    <area>0,60,370,380</area>
    4463    <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
    4564    <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
    4665    <fcnfont name="active" function="active"/>
     
    4867    <showarrow>no</showarrow>
    4968   </listbtnarea>
    5069
    51    <listbtnarea name="actionlist" draworder="0">
    52     <area>390,0,370,360</area>
     70   <textarea name="rightdesc" draworder="1" align="center">
     71    <font>info</font>
     72    <area>390,40,370,20</area>
     73    <value>Actions</value>
     74   </textarea>
     75
     76   <listbtnarea name="rightlist" draworder="0">
     77    <area>390,60,370,380</area>
    5378    <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
    5479    <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
    5580    <fcnfont name="active" function="active"/>
     
    6085  </container>
    6186
    6287  <container name="keys_layer">
    63    <area>20,400,780,180</area>
     88   <area>20,450,780,210</area>
    6489   <textbutton name="action_one" draworder="0">
    65     <position>20,20</position>
     90    <position>20,0</position>
    6691    <image function="on" filename="kb-button-on.png"/>
    6792    <image function="off" filename="kb-button-off.png"/>
    6893    <font>keys</font>
    6994   </textbutton>
    7095
    7196   <textbutton name="action_two" draworder="0">
    72     <position>200,20</position>
     97    <position>200,0</position>
    7398    <image function="on" filename="kb-button-on.png"/>
    7499    <image function="off" filename="kb-button-off.png"/>
    75100    <font>keys</font>
    76101   </textbutton>
    77102
    78103   <textbutton name="action_three" draworder="0">
    79     <position>390,20</position>
     104    <position>390,0</position>
    80105    <image function="on" filename="kb-button-on.png"/>
    81106    <image function="off" filename="kb-button-off.png"/>
    82107    <font>keys</font>
    83108   </textbutton>
    84109
    85110   <textbutton name="action_four" draworder="0">
    86     <position>580,20</position>
     111    <position>580,0</position>
    87112    <image function="on" filename="kb-button-on.png"/>
    88113    <image function="off" filename="kb-button-off.png"/>
    89114    <font>keys</font>
     
    91116
    92117   <textarea name="description" draworder="1" allign="left">
    93118    <font>info</font>
    94     <area>30,100,740,140</area>
     119    <area>30,70,740,110</area>
    95120    <multiline>yes</multiline>
    96121   </textarea>
    97122