Ticket #2078: 2078-v2.patch

File 2078-v2.patch, 37.6 KB (added by mfgalizi, 14 years ago)

Fixes problems still present in v1

  • mythcontrols/actionset.h

     
    5858    QStringList GetActionStrings(const QString &context_name) const;
    5959    QString     GetKeyString(const ActionID &id) const;
    6060    QStringList GetKeys(const ActionID &id) const;
     61    QStringList GetContextKeys(const QString &context_name) const;
     62    QStringList GetAllKeys(void) const;
    6163    QString     GetDescription(const ActionID &id) const;
    6264    const ActionList& GetActions(const QString &key) const;
    6365    /// \brief Returns the appropriate container of modified actions
  • mythcontrols/keygrabber.h

     
    9494    Q_OBJECT
    9595
    9696  public:
    97     enum actions { kSave, kCancel, };
     97    enum actions { kSave, kChangeView, kCancel, };
    9898
    9999    /// \brief Create a new action window. Does not pop-up menu.
    100100    OptionsMenu(MythMainWindow *window);
     
    103103    int GetOption(void) { return ExecPopup(this,SLOT(Cancel())); }
    104104
    105105  public slots:
    106     void Save(void)     { done(OptionsMenu::kSave);   }
    107     void Cancel(void)   { done(OptionsMenu::kCancel); }
     106    void Save(void)       { done(OptionsMenu::kSave);       }
     107    void ChangeView(void) { done(OptionsMenu::kChangeView); }
     108    void Cancel(void)     { done(OptionsMenu::kCancel);     }
    108109};
    109110
    110111
  • mythcontrols/mythcontrols.cpp

     
    22/**
    33 * @file mythcontrols.cpp
    44 * @author Micah F. Galizia <mfgalizi@csd.uwo.ca>
    5  * @brief Main header for mythcontrols.
     5 * @brief Main mythcontrols class.
    66 *
    77 * Note that the keybindings are fetched all at once, and cached for
    88 * this host.  This avoids pelting the database everytime the user
     
    4040#include "mythcontrols.h"
    4141#include "keygrabber.h"
    4242
    43 static QString key_to_display(const QString &key);
    44 static QString display_to_key(const QString &key);
    45 
    4643#define LOC QString("MythControls: ")
    4744#define LOC_ERR QString("MythControls, Error: ")
     45#define CAPTION_CONTEXT QString("Contexts")
     46#define CAPTION_ACTION QString("Actions")
     47#define CAPTION_KEY QString("Keys")
    4848
    4949/** \fn MythControls::MythControls(MythMainWindow*, bool&)
    5050 *  \brief Creates a new MythControls wizard
     
    5353 */
    5454MythControls::MythControls(MythMainWindow *parent, bool &ok)
    5555    : MythThemedDialog(parent, "controls", "controls-", "controls"),
     56      m_currentView(kActionsByContext),
    5657      m_focusedUIElement(NULL),
    5758      m_leftList(NULL),        m_rightList(NULL),
    5859      m_description(NULL),
     
    7172    m_rightListType = kActionList;
    7273
    7374    LoadData(gContext->GetHostName());
    74     RefreshKeyInformation();
    7575
     76    /* start off with the actions by contexts view */
     77    m_currentView = kActionsByContext;
     78    SetListContents(m_leftList, m_bindings->GetContexts(), true);
     79    UpdateRightList();
     80
    7681    connect(m_leftList,  SIGNAL(itemSelected( UIListBtnTypeItem*)),
    7782            this,        SLOT(  LeftSelected( UIListBtnTypeItem*)));
    7883    connect(m_rightList, SIGNAL(itemSelected( UIListBtnTypeItem*)),
     
    221226    RefreshKeyInformation();
    222227}
    223228
     229/// \brief Chagne the view.
     230void MythControls::ChangeView(void)
     231{
     232    ViewMenu popup(gContext->GetMainWindow());
     233    QStringList contents;
     234    QString leftcaption, rightcaption;
     235
     236    switch(popup.GetOption())
     237    {
     238        case ViewMenu::kContextAction:
     239            leftcaption = tr(CAPTION_CONTEXT);
     240            rightcaption = tr(CAPTION_ACTION);
     241            m_currentView = kActionsByContext;
     242            contents = m_bindings->GetContexts();
     243            break;
     244        case ViewMenu::kContextKey:
     245            leftcaption = tr(CAPTION_CONTEXT);
     246            rightcaption = tr(CAPTION_KEY);
     247            m_currentView = kKeysByContext;
     248            contents = m_bindings->GetContexts();
     249            break;
     250        case ViewMenu::kKeyContext:
     251            leftcaption = tr(CAPTION_KEY);
     252            rightcaption = tr(CAPTION_CONTEXT);
     253            m_currentView = kContextsByKey;
     254            contents = m_bindings->GetKeys();
     255            break;
     256        default:
     257            break;
     258    }
     259
     260    m_leftDescription->SetText(leftcaption);
     261    m_rightDescription->SetText(rightcaption);
     262
     263    SetListContents(m_leftList, contents, true);
     264    RefreshKeyInformation();
     265    UpdateRightList();
     266
     267    if (m_focusedUIElement != m_leftList)
     268    {
     269        m_focusedUIElement->looseFocus();
     270        m_focusedUIElement = m_leftList;
     271        m_focusedUIElement->takeFocus();
     272    }
     273}
     274
    224275void MythControls::keyPressEvent(QKeyEvent *e)
    225276{
    226277    bool handled = false;
     
    238289            m_focusedUIElement->looseFocus();
    239290
    240291            OptionsMenu popup(gContext->GetMainWindow());
    241             if (OptionsMenu::kSave == popup.GetOption())
    242                 Save();
    243292
     293            switch(popup.GetOption())
     294            {
     295                case OptionsMenu::kSave:
     296                    Save();
     297                    break;
     298                case OptionsMenu::kChangeView:
     299                    ChangeView();
     300                    break;
     301                default:
     302                    break;
     303            }
     304
    244305            m_focusedUIElement->takeFocus();
    245306        }
    246307        else if (action == "SELECT")
     
    248309            if (m_focusedUIElement == m_leftList)
    249310                ChangeListFocus(m_rightList, m_leftList);
    250311            else if (m_focusedUIElement == m_rightList)
    251                 ChangeButtonFocus(0);
     312            {
     313                if (m_currentView == kActionsByContext)
     314                    ChangeButtonFocus(0);
     315                else
     316                    handled = false;
     317            }
    252318            else
    253319            {
    254320                QString key = GetCurrentKey();
     
    327393            else if (m_focusedUIElement == m_rightList)
    328394                m_rightList->MoveDown(UIListBtnType::MovePage);
    329395        }
    330         else if (action == "1")
    331         {
    332             if ((m_leftListType  != kContextList) ||
    333                 (m_rightListType != kActionList))
    334             {
    335                 m_leftListType  = kContextList;
    336                 m_rightListType = kActionList;
    337                 UpdateLists();
    338 
    339                 if (m_focusedUIElement != m_leftList)
    340                 {
    341                     ChangeListFocus(m_leftList,
    342                                     (m_focusedUIElement == m_rightList) ?
    343                                     m_rightList : NULL);
    344                 }
    345             }
    346             else
    347             {
    348                 handled = false;
    349             }
    350         }
    351         else if (action == "2")
    352         {
    353             if ((m_leftListType  != kContextList) ||
    354                 (m_rightListType != kKeyList))
    355             {
    356                 m_leftListType  = kContextList;
    357                 m_rightListType = kKeyList;
    358                 UpdateLists();
    359 
    360                 if (m_focusedUIElement != m_leftList)
    361                 {
    362                     ChangeListFocus(m_leftList,
    363                                     (m_focusedUIElement == m_rightList) ?
    364                                     m_rightList : NULL);
    365                 }
    366             }
    367             else
    368             {
    369                 handled = false;
    370             }
    371         }
    372         else if (action == "3")
    373         {
    374             if ((m_leftListType  != kKeyList) ||
    375                 (m_rightListType != kContextList))
    376             {
    377                 m_leftListType  = kKeyList;
    378                 m_rightListType = kContextList;
    379                 UpdateLists();
    380 
    381                 if (m_focusedUIElement != m_leftList)
    382                 {
    383                     ChangeListFocus(m_leftList,
    384                                     (m_focusedUIElement == m_rightList) ?
    385                                     m_rightList : NULL);
    386                 }
    387             }
    388             else
    389             {
    390                 handled = false;
    391             }
    392         }
    393396        else
    394397        {
    395398            handled = false;
     
    397400    }
    398401
    399402    if (!handled)
    400     {
    401         handled |= (!escape && JumpTo(e));
    402         if (!handled)
    403             MythThemedDialog::keyPressEvent(e);
    404     }
     403        MythThemedDialog::keyPressEvent(e);
    405404}
    406405
    407 /** \fn MythControls::JumpTo(QKeyEvent*)
    408  *  \brief Jump to a particular key binding
    409  *  \param e key event to use as jump
    410  */
    411 bool MythControls::JumpTo(QKeyEvent *e)
    412 {
    413     UIListBtnType *list = NULL;
    414 
    415     list = ((m_focusedUIElement == m_leftList) &&
    416             (m_leftListType     == kKeyList)) ? m_leftList  : list;
    417     list = ((m_focusedUIElement == m_rightList) &&
    418             (m_rightListType    == kKeyList)) ? m_rightList : list;
    419 
    420     if (!list)
    421         return false;
    422 
    423     QString key = e->text();
    424     if (key.left(6) == "remote")
    425     {
    426         key = key_to_display(key);
    427     }
    428     else
    429     {
    430         key = QString(QKeySequence(e->key()));
    431 
    432         if (key.isEmpty())
    433             return false;
    434 
    435         QString modifiers = "";
    436 
    437         if (e->state() & Qt::ShiftButton)
    438             modifiers += "Shift+";
    439         if (e->state() & Qt::ControlButton)
    440             modifiers += "Ctrl+";
    441         if (e->state() & Qt::AltButton)
    442             modifiers += "Alt+";
    443         if (e->state() & Qt::MetaButton)
    444             modifiers += "Meta+";
    445 
    446         key = modifiers + key;
    447     }
    448 
    449     uint len = 1024; // infinity
    450     if (list == m_rightList)
    451     {
    452         key = key + " ";
    453         len = key.length();
    454     }
    455 
    456     UIListBtnTypeItem *b;
    457     for (b = list->GetItemFirst(); b; b = list->GetItemNext(b))
    458     {
    459         if (b->text().left(len) == key)
    460             break;
    461     }
    462 
    463     if (!b)
    464         return false;
    465 
    466     int curpos = list->GetItemPos(list->GetItemCurrent());
    467     int newpos = list->GetItemPos(b);
    468 
    469     if (newpos > curpos)
    470         list->MoveDown(newpos - curpos);
    471     else if (newpos < curpos)
    472         list->MoveUp(curpos - newpos);
    473 
    474     return true;
    475 }
    476 
    477406/** \fn MythControls::LeftSelected(UIListBtnTypeItem*)
    478407 *  \brief Refreshes the right list when an item in the
    479408 *         left list is selected
     
    482411{
    483412    m_leftList->refresh();
    484413    m_rightList->blockSignals(true);
    485     RefreshRightList();
     414    UpdateRightList();
    486415    m_rightList->blockSignals(false);
    487416    m_rightList->refresh();
    488417}
     
    497426    RefreshKeyInformation();
    498427}
    499428
    500 /** \fn MythControls::RefreshRightList(void)
    501  *  \brief Load the appropriate actions into the action list
     429
     430/** \brief Set the contents of a list.
     431 *  \param list The list being changed.
     432 *  \param contents The contents of the list.
     433 *  \param arrows True to draw with arrows, otherwise arrows are not drawn.
    502434 */
    503 void MythControls::RefreshRightList(void)
     435void MythControls::SetListContents(
     436    UIListBtnType *uilist, const QStringList &contents, bool arrows)
    504437{
    505     m_rightList->Reset();
     438    uilist->blockSignals(true);
    506439
    507     if (!m_leftList->GetItemCurrent())
    508         return;
     440    // remove all strings from the current list
     441    uilist->Reset();
    509442
    510     if (m_leftListType == kContextList)
     443    // add each new string
     444    for (size_t i = 0; i < contents.size(); i++)
    511445    {
    512         if (m_rightListType == kActionList)
    513         {
    514             /* add all of the actions to the context list */
    515             QString context = m_leftList->GetItemCurrent()->text();
    516             QStringList *actions = m_contexts[context];
    517             if (!actions || actions->empty())
    518             {
    519                 VERBOSE(VB_IMPORTANT, LOC_ERR +
    520                         QString("Unable to find actions for context %1")
    521                         .arg(context));
    522 
    523                 return;
    524             }
    525 
    526             for (uint i = 0; i < actions->size(); i++)
    527                 new UIListBtnTypeItem(m_rightList, (*actions)[i]);
    528         }
    529         else if (m_rightListType == kKeyList)
    530         {
    531             /* add all of the actions to the context list */
    532             QString context = m_leftList->GetItemCurrent()->text();
    533             const BindingList *list = m_contextToBindingsMap[context];
    534             if (!list)
    535             {
    536                 VERBOSE(VB_IMPORTANT, LOC_ERR+
    537                         QString("Unable to find keys for context %1")
    538                         .arg(context));
    539 
    540                 return;
    541             }
    542 
    543             BindingList::const_iterator it = list->begin();
    544             for (; it != list->end(); ++it)
    545             {
    546                 new UIListBtnTypeItem(
    547                     m_rightList,
    548                     key_to_display((*it)->key) + " => " + (*it)->action);
    549             }
    550         }
     446        UIListBtnTypeItem *item = new UIListBtnTypeItem(uilist, contents[i]);
     447        item->setDrawArrow(arrows);
    551448    }
    552     else if ((m_leftListType == kKeyList) && (m_rightListType == kContextList))
    553     {
    554         QString key = display_to_key(m_leftList->GetItemCurrent()->text());
    555         const BindingList *list = m_keyToBindingsMap[key];
    556         if (!list)
    557         {
    558             VERBOSE(VB_IMPORTANT, LOC + QString(
    559                         "Unable to find actions for key %1").arg(key));
    560             return;
    561         }
    562449
    563         BindingList::const_iterator it = list->begin();
    564         const Binding *b = *it;
    565         for (uint i = 0; i < m_sortedContexts.size(); i++)
    566         {
    567             const QString context = m_sortedContexts[i];
    568             QString action  = "<none>";
    569 
    570             if (b && b->context == context)
    571             {
    572                 action = b->action;
    573                 ++it;
    574                 b = (it != list->end()) ? *it : NULL;
    575             }
    576 
    577             new UIListBtnTypeItem(m_rightList, context + " => " + action);
    578         }
    579     }
     450    uilist->blockSignals(false);
     451    uilist->refresh();
    580452}
    581453
    582 QString MythControls::RefreshKeyInformationKeyList(void)
     454/** \brief Update the right list. */
     455void MythControls::UpdateRightList(void)
    583456{
    584     if ((m_leftListType != kKeyList) && (m_rightListType != kKeyList))
    585         return "";
     457    // get the selected item in the right list.
     458    UIListBtnTypeItem *item = m_leftList->GetItemCurrent();
    586459
    587     QString action  = GetCurrentAction();
    588     QString context = GetCurrentContext();
    589 
    590     if (action.isEmpty())
    591         return "";
    592 
    593     QString desc = m_bindings->GetActionDescription(context, action);
    594    
    595     BindingList *list = NULL;
    596     if (m_leftListType == kKeyList && m_rightListType == kContextList)
     460    if (item != NULL)
    597461    {
    598         list = m_keyToBindingsMap[display_to_key(GetCurrentKey())];
    599     }
    600     else if (m_leftListType == kContextList && m_rightListType == kKeyList)
    601     {
    602         list = m_contextToBindingsMap[context];
    603     }
     462        QString rtstr = item->text();
    604463
    605     if (!list)
    606         return desc;
    607 
    608     QString searchKey = QString::null;
    609     if (m_rightListType == kContextList)
    610     {
    611         searchKey = context;
    612     }
    613     else if (m_rightListType == kActionList)
    614     {
    615         searchKey = action;
    616     }
    617     else if (m_rightListType == kKeyList)
    618     {
    619         searchKey = display_to_key(GetCurrentKey());
    620     }
    621 
    622     const Binding *binding = NULL;
    623     for (BindingList::const_iterator it = list->begin();
    624          it != list->end(); ++it)
    625     {
    626         switch (m_rightListType)
     464        switch(m_currentView)
    627465        {
    628             case kContextList:
    629                 if ((*it)->context == searchKey)
    630                     binding = *it;
    631                 break;
    632             case kActionList:
    633                 if ((*it)->action == searchKey)
    634                     binding = *it;
    635                 break;
    636             case kKeyList:
    637                 if ((*it)->key == searchKey)
    638                     binding = *it;
    639                 break;
    640         }
    641 
    642         if (binding)
     466        case kActionsByContext:
     467            SetListContents(m_rightList, *(m_contexts[rtstr]));
    643468            break;
     469        case kKeysByContext:
     470            SetListContents(m_rightList, m_bindings->GetContextKeys(rtstr));
     471            break;
     472        case kContextsByKey:
     473            SetListContents(m_rightList, m_bindings->GetKeyContexts(rtstr));
     474            break;
     475        }
    644476    }
    645    
    646     if (!binding)
    647         return desc;
    648 
    649 
    650     if (desc.isEmpty() && (context != binding->contextFrom))
    651     {
    652         desc = m_bindings->GetActionDescription(
    653             binding->contextFrom, action);
    654     }
    655 
    656     desc += "\n" + tr("Binding comes from %1 context")
    657         .arg(binding->contextFrom);
    658 
    659     return desc;
     477    else
     478        VERBOSE(VB_IMPORTANT, QString("Left List Returned Null!"));
    660479}
    661480
    662481/** \fn MythControls::RefreshKeyInformation(void)
     
    674493        return;
    675494    }
    676495
    677     if ((m_leftListType == kKeyList) || (m_rightListType == kKeyList))
    678     {
    679         m_description->SetText(RefreshKeyInformationKeyList());
    680         return;
    681     }
    682 
    683496    const QString context = GetCurrentContext();
    684497    const QString action  = GetCurrentAction();
    685498
     
    690503    for (uint i = 0; (i < keys.count()) &&
    691504             (i < Action::kMaximumNumberOfBindings); i++)
    692505    {
    693         m_actionButtons[i]->setText(key_to_display(keys[i]));
     506        m_actionButtons[i]->setText(keys[i]);
    694507    }
    695508}
    696509
     
    731544QString MythControls::GetCurrentAction(void) const
    732545{
    733546    if (m_leftListType == kActionList)
    734         return m_leftList->GetItemCurrent()->text();
     547    {
     548        if (m_leftList && m_leftList->GetItemCurrent())
     549            return QDeepCopy<QString>(m_leftList->GetItemCurrent()->text());
     550        return QString::null;
     551    }
    735552
    736553    if (m_focusedUIElement == m_leftList)
    737554        return QString::null;
    738555
     556    if (!m_rightList || !m_rightList->GetItemCurrent())
     557        return QString::null;
     558
    739559    QString desc = m_rightList->GetItemCurrent()->text();
    740560    if (m_leftListType == kContextList && m_rightListType == kActionList)
    741         return desc;
     561        return QDeepCopy<QString>(desc);
    742562
    743563    int loc = desc.find(" => ");
    744564    if (loc == -1)
     
    794614    return desc.mid(loc + 4);
    795615}
    796616
    797 /** \fn MythControls::LoadAll(const QString&)
     617/** \fn MythControls::LoadData(const QString&)
    798618 *  \brief Load the settings for a particular host.
    799619 *  \param hostname The host to load settings for.
    800620 */
     
    804624    m_bindings = new KeyBindings(hostname);
    805625    m_sortedContexts = m_bindings->GetContexts();
    806626
    807     m_sortedKeys.clear();
    808 
    809627    /* Alphabetic order, but jump and global at the top  */
    810628    m_sortedContexts.sort();
    811629    m_sortedContexts.remove(ActionSet::kJumpContext);
     
    822640        actions.sort();
    823641        m_contexts.insert(m_sortedContexts[i], new QStringList(actions));
    824642    }
    825 
    826     RefreshKeyBindings();
    827     UpdateLists();
    828643}
    829644
    830645/** \fn MythControls::DeleteKey(void)
     
    846661        return;
    847662    }
    848663
    849     BindingList *list = m_keyToBindingsMap[key];
    850     Binding *binding = NULL;
     664    ConfirmMenu popup(gContext->GetMainWindow(), tr("Delete this binding?"));
    851665
    852     for (BindingList::iterator it = list->begin(); it != list->end(); ++it)
    853     {
    854         Binding *b = *it;
    855         if (b->context == context)
    856             binding = b;
    857     }
    858 
    859     if (!binding)
    860     {
    861         InvalidBindingPopup popup(gContext->GetMainWindow());
    862         popup.GetOption();
     666    if (popup.GetOption() != ConfirmMenu::kConfirm)
    863667        return;
    864     }
    865668
    866     if (binding->contextFrom != context)
     669    if (!m_bindings->RemoveActionKey(context, action, key))
    867670    {
    868         ConfirmMenu popup(gContext->GetMainWindow(),
    869                           tr("Delete this key binding from context %1?")
    870                           .arg(binding->contextFrom));
    871 
    872         if (popup.GetOption() != ConfirmMenu::kConfirm)
    873             return;
    874     }
    875     else
    876     {
    877         ConfirmMenu popup(gContext->GetMainWindow(),
    878                           tr("Delete this binding?"));
    879 
    880         if (popup.GetOption() != ConfirmMenu::kConfirm)
    881             return;
    882     }
    883 
    884     if (!m_bindings->RemoveActionKey(binding->contextFrom, action, key))
    885     {
    886671        InvalidBindingPopup popup(gContext->GetMainWindow());
    887672        popup.GetOption();
    888673        return;
    889674    }
    890675
    891     RefreshKeyBindings();
    892676    RefreshKeyInformation();
    893677}
    894678
     
    977761        m_bindings->AddActionKey(context, action, key);
    978762    }
    979763
    980     RefreshKeyBindings();
    981764    RefreshKeyInformation();
    982765}
    983766
    984 /** \fn MythControls::AddBindings(QDict<Binding>&, const QString&,
    985                                   const QString&, int)
    986  *  \brief Add bindings to QDict<Binding> for specified context
    987  *  \param bindings the QDict to which to add the bindings
    988  *  \param context the context to grab keybindings from
    989  *  \param contextParent the context whose keybindings are being calculated
    990  *  \param bindlevel the bind level associated with this context
     767/** \fn ViewMenu::ViewMenu(MythMainWindow*, ViewType)
     768 *  \brief Creates a new view dialog box.
     769 *  \param window The main MythTV window.
    991770 */
    992 void MythControls::AddBindings(QDict<Binding> &bindings,
    993                                const QString    &context,
    994                                const QString    &contextParent,
    995                                int               bindlevel)
     771ViewMenu::ViewMenu(MythMainWindow *window) :
     772    MythPopupBox(window, "mcviewmenu")
    996773{
    997     QStringList actions = m_bindings->GetActions(context);
    998 
    999     for (uint i = 0; i < actions.size(); i++)
    1000     {
    1001         QString action = actions[i];
    1002         QStringList keys = m_bindings->GetActionKeys(context, action);
    1003 
    1004         for (uint j = 0; j < keys.size(); j++)
    1005         {
    1006             Binding *b = bindings.find(keys[j]);
    1007 
    1008             if (!b)
    1009             {
    1010                 b = new Binding(keys[j], contextParent,
    1011                                 context, action, bindlevel);
    1012 
    1013                 bindings.insert(keys[j], b);
    1014             }
    1015             else if (b->bindlevel == bindlevel)
    1016             {
    1017                 b->action += ", " + action;
    1018             }
    1019         }
    1020     }
     774    addLabel(tr("Change View"), Large, false);
     775    addButton(tr("Actions By Context"), this, SLOT(ActionsByContext()));
     776    addButton(tr("Contexts By Key"), this, SLOT(ContextsByKey()));
     777    addButton(tr("Keys By Context"), this, SLOT(KeysByContext()));
     778    addButton(tr("Cancel"), this, SLOT(Cancel()))->setFocus();
    1021779}
    1022780
    1023 /** \fn MythControls::GetKeyBindings(const QString&)
    1024  *  \brief Create a BindingList for the specified context
    1025  *  \param context the context for which a BindingList should be created
    1026  *  \return a BindingList with "auto delete" property enabled.
    1027  */
    1028 BindingList *MythControls::GetKeyBindings(const QString &context)
    1029 {
    1030     QDict<Binding> bindings;
    1031     for (uint i = 0; i < m_sortedContexts.size(); i++)
    1032         AddBindings(bindings, m_sortedContexts[i], context, i);
    1033 
    1034     QStringList keys;
    1035     for (QDictIterator<Binding> it(bindings); it.current(); ++it)
    1036         keys.append(it.currentKey());
    1037 
    1038     SortKeyList(keys);
    1039 
    1040     BindingList *blist = new BindingList();
    1041     blist->setAutoDelete(true);
    1042 
    1043     QStringList::const_iterator kit = keys.begin();
    1044     for (; kit != keys.end(); ++kit)
    1045         blist->append(bindings[*kit]);
    1046 
    1047     return blist;
    1048 }
    1049 
    1050 /** \fn MythControls::RefreshKeyBindings(void)
    1051  *  \brief Refresh binding information
    1052  */
    1053 void MythControls::RefreshKeyBindings(void)
    1054 {
    1055     m_contextToBindingsMap.clear();
    1056     m_keyToBindingsMap.clear();
    1057     m_contextToBindingsMap.setAutoDelete(true);
    1058     m_keyToBindingsMap.setAutoDelete(true);
    1059 
    1060     for (uint i = 0; i < m_sortedContexts.size(); i++)
    1061     {
    1062         QString context = m_sortedContexts[i];
    1063         BindingList *list = GetKeyBindings(context);
    1064         m_contextToBindingsMap.insert(context, list);
    1065 
    1066         BindingList::const_iterator it = list->begin();
    1067         for (; it != list->end(); ++it)
    1068         {
    1069             BindingList *list = m_keyToBindingsMap.find((*it)->key);
    1070 
    1071             if (!list)
    1072             {
    1073                 list = new BindingList();
    1074                 m_keyToBindingsMap.insert((*it)->key, list);
    1075             }
    1076 
    1077             m_sortedKeys.append((*it)->key);
    1078             list->append(*it);
    1079         }
    1080     }
    1081 
    1082     SortKeyList(m_sortedKeys);
    1083 }
    1084 
    1085 /** \fn MythControls::SortKeyList(QStringList&)
    1086  *  \brief Sort a list of keys, removing duplicates
    1087  *  \param keys the list of keys to sort
    1088  */
    1089 void MythControls::SortKeyList(QStringList &keys)
    1090 {
    1091     QStringList tmp;
    1092     QStringList::const_iterator it = keys.begin();
    1093     for (; it != keys.end(); ++it)
    1094     {
    1095         QString key     = *it;
    1096         QString keydesc = (key.left(6) == "remote") ? "0 " : "3 ";
    1097 
    1098         keydesc = ((key.length() > 1) && !(key.left(6) == "remote") &&
    1099                    (key.find("+", 1) >= 0)) ? "4 " : keydesc;
    1100 
    1101         if (key.length() == 1)
    1102         {
    1103             QChar::Category cat = key[0].category();
    1104             keydesc = (QChar::Letter_Uppercase    == cat) ? "2 " : "5 ";
    1105             keydesc = (QChar::Number_DecimalDigit == cat) ? "1 " : keydesc;
    1106         }
    1107 
    1108         tmp.push_back(keydesc + key);
    1109     }
    1110     tmp.sort();
    1111 
    1112     keys.clear();
    1113 
    1114     QString prev = QString::null;
    1115     for (it = tmp.begin(); it != tmp.end(); ++it)
    1116     {
    1117         QString cur = (*it).mid(2);
    1118         if (cur != prev)
    1119         {
    1120             keys.append(cur);
    1121             prev = cur;
    1122         }
    1123     }
    1124 }
    1125 
    1126 /// NOTE: This can not be a static method because the QObject::tr()
    1127 ///       translations do not work reliably in static initializers.
    1128 QString MythControls::GetTypeDesc(ListType type) const
    1129 {
    1130     switch (type)
    1131     {
    1132         case kContextList:
    1133             return tr("Contexts");
    1134             break;
    1135         case kKeyList:
    1136             return tr("Keys");
    1137             break;
    1138         case kActionList:
    1139             return tr("Actions");
    1140             break;
    1141         default:
    1142             return "";
    1143     }
    1144 }
    1145 
    1146 /** \fn MythControls::UpdateLists(void)
    1147  *  \brief Redisplays both the left and right lists and fixes focus issues.
    1148  */
    1149 void MythControls::UpdateLists(void)
    1150 {
    1151     m_rightList->blockSignals(true);
    1152     m_leftList->blockSignals(true);
    1153     m_leftList->Reset();
    1154 
    1155     if (m_leftListType == kContextList)
    1156     {
    1157         for (uint i = 0; i < m_sortedContexts.size(); i++)
    1158         {
    1159             UIListBtnTypeItem *item = new UIListBtnTypeItem(
    1160                 m_leftList, m_sortedContexts[i]);
    1161 
    1162             item->setDrawArrow(true);
    1163         }
    1164     }
    1165     else if (m_leftListType == kKeyList)
    1166     {
    1167         for (uint i = 0; i < m_sortedKeys.size(); i++)
    1168         {
    1169             UIListBtnTypeItem *item = new UIListBtnTypeItem(
    1170                 m_leftList, key_to_display(m_sortedKeys[i]));
    1171 
    1172             item->setDrawArrow(true);
    1173         }
    1174     }
    1175 
    1176     RefreshRightList();
    1177 
    1178     m_rightList->blockSignals(false);
    1179     m_leftList->blockSignals(false);
    1180 
    1181     m_leftList->refresh();
    1182     m_rightList->refresh();
    1183 
    1184     if (m_leftDescription)
    1185         m_leftDescription->SetText(GetTypeDesc(m_leftListType));
    1186 
    1187     if (m_rightDescription)
    1188         m_rightDescription->SetText(GetTypeDesc(m_rightListType));
    1189 }
    1190 
    1191 static QString key_to_display(const QString &key)
    1192 {
    1193     if (key.left(6) == "remote")
    1194         return "[" + key.mid(6) + "]";
    1195 
    1196     return key;
    1197 }
    1198 
    1199 static QString display_to_key(const QString &key)
    1200 {
    1201     if (key.left(1) == "[" && key != "[")
    1202         return "remote" + key.mid(1, key.length() - 2);
    1203 
    1204     return key;
    1205 }
    1206 
    1207781/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythcontrols/keybindings.cpp

     
    4949    LoadJumppoints();
    5050}
    5151
     52/** \brief Returns a list of all keys bound to an action. */
     53QStringList KeyBindings::GetKeys(void) const
     54{
     55    return m_actionSet.GetAllKeys();
     56}
     57
    5258/** \fn KeyBindings::GetContexts(void) const
    5359 *  \brief Returns a list of the context names.
    5460 *  \note The returned list is a copy and can be modified without side-effects.
    5561 */
    5662QStringList KeyBindings::GetContexts(void) const
    5763{
    58     return QDeepCopy<QStringList>(m_actionSet.GetContextStrings());
     64    QStringList ctxts =
     65        QDeepCopy<QStringList>(m_actionSet.GetContextStrings());
     66    ctxts.sort();
     67    return ctxts;
    5968}
    6069
    6170/** \fn KeyBindings::GetActions(const QString&) const
     
    95104        (m_actionSet.GetKeys(ActionID(context_name, action_name)));
    96105}
    97106
     107/** \fn KeyBindings::GetContextKeys(const QString &) const
     108 *  \brief Get the keys within a context.
     109 *  \param context The context name.
     110 *  \return A list of the keys in the context.
     111 */
     112QStringList KeyBindings::GetContextKeys(const QString &context) const
     113{
     114    return m_actionSet.GetContextKeys(context);
     115}
     116
     117/** \fn KeyBindings::GetKeyContexts(const QString &) const
     118 *  \brief Get the context names in which a key is bound.
     119 *  \return A list of context names in which a key is bound.
     120 */
     121QStringList KeyBindings::GetKeyContexts(const QString &key) const
     122{
     123    ActionList actions = m_actionSet.GetActions(key);
     124    QStringList contexts;
     125
     126    for (size_t i = 0; i < actions.size(); i++)
     127    {
     128        QString context = actions[i].GetContext();
     129        if (!contexts.contains(context))
     130            contexts.push_back(context);
     131    }
     132
     133    return contexts;
     134}
     135
    98136/** \fn KeyBindings::GetActionDescription(const QString&,const QString&) const
    99137 *  \brief Get an action's description.
    100138 *  \param context_name The name of the context.
  • mythcontrols/actionset.cpp

     
    6262
    6363    ActionList &ids = m_keyToActionMap[key];
    6464    ids.push_back(id);
    65     SetModifiedFlag(id, true); 
     65    SetModifiedFlag(id, true);
    6666
    6767    return true;
    6868}
     
    7575 *
    7676 *  \param id The action identifier to remove from.
    7777 *  \param key The key to remove.
     78 *
     79 *  \todo Remove the actionlist from the m_keyToActionMap if the key
     80 *        is no longer bound to any actions.
    7881 */
    7982bool ActionSet::Remove(const ActionID &id, const QString &key)
    8083{
     
    8790        return false;
    8891
    8992    m_keyToActionMap[key].remove(id);
     93
     94    // remove the key if there isn't anything bound to it.
     95    if (m_keyToActionMap[key].isEmpty())
     96        m_keyToActionMap.remove(key);
     97
    9098    SetModifiedFlag(id, true);
    9199
    92     return true;           
     100    return true;
    93101}
    94102
    95103/** \fn ActionSet::Replace(const ActionID&,const QString&,const QString&)
     
    118126    m_keyToActionMap[newkey].push_back(id);
    119127    SetModifiedFlag(id, true);
    120128
    121     return true;           
     129    return true;
    122130}
    123131
    124132/** \fn ActionSet::SetModifiedFlag(const ActionID&, bool)
     
    242250    return keys;
    243251}
    244252
     253QStringList ActionSet::GetContextKeys(const QString & context_name) const
     254{
     255    QStringList keys;
     256    Context *c = m_contexts[context_name];
     257
     258    QDictIterator<Action> it(*c);
     259    for (;it.current(); ++it)
     260    {
     261        QStringList akeys = (*it)->GetKeys();
     262        for (size_t i = 0; i < akeys.size(); i++)
     263        {
     264                keys.append(akeys[i]);
     265        }
     266        keys.sort();
     267    }
     268
     269    return keys;
     270}
     271
     272/** \brief Get all keys (from every context) to which an action is bound.
     273 */
     274QStringList ActionSet::GetAllKeys(void) const
     275{
     276    QStringList keys;
     277
     278    QMap<QString, ActionList>::ConstIterator it;
     279
     280    for (it = m_keyToActionMap.begin(); it != m_keyToActionMap.end(); ++it)
     281        keys.push_back(it.key());
     282
     283    return keys;
     284}
     285
    245286/** \fn ActionSet::GetDescription(const ActionID&) const
    246287 *  \brief Returns the description of an action by its identifier.
    247288 *         (note: result not thread-safe)
  • mythcontrols/mythcontrols.h

     
    2929
    3030#include "keybindings.h"
    3131
    32 class Binding
     32
     33typedef enum { kActionsByContext, kKeysByContext, kContextsByKey, } ViewType;
     34
     35/** \class ViewMenu
     36 *  \brief Prompts the user to change the view.
     37 */
     38class ViewMenu : public MythPopupBox
    3339{
     40    Q_OBJECT
     41
    3442  public:
    35     Binding(const QString &_key,         const QString &_context,
    36             const QString &_contextFrom, const QString &_action,
    37             int            _bindlevel) :
    38         key(_key), context(_context),
    39         contextFrom(_contextFrom), action(_action), bindlevel(_bindlevel) {}
     43    ViewMenu(MythMainWindow *window);
    4044
    41   public:
    42     QString key;
    43     QString context;
    44     QString contextFrom;
    45     QString action;
    46     int     bindlevel;
     45    /// \brief Execute the option popup.
     46    int GetOption(void) { return ExecPopup(this, SLOT(Cancel())); }
     47
     48    /// \brief The available views
     49    enum actions { kContextAction, kContextKey, kKeyContext, kCancel, };
     50
     51  public slots:
     52    void ActionsByContext(void) { done(ViewMenu::kContextAction); }
     53    void KeysByContext(void)    { done(ViewMenu::kContextKey);    }
     54    void ContextsByKey(void)    { done(ViewMenu::kKeyContext);    }
     55    void Cancel(void)           { done(ViewMenu::kCancel);        }
    4756};
    48 typedef QPtrList<Binding> BindingList;
    4957
    5058/** \class MythControls
    5159 *  \brief The myth controls configuration class.
     
    7785    // Commands
    7886    bool    LoadUI(void);
    7987    void    RefreshKeyInformation(void);
    80     QString RefreshKeyInformationKeyList(void);
    81     void    RefreshRightList(void);
    82     void    UpdateLists(void);
    8388    void    LoadData(const QString &hostname);
    8489    void    ChangeButtonFocus(int direction);
    8590    void    ChangeListFocus(UIListBtnType *focus, UIListBtnType *unfocus);
    86     void    AddBindings(QDict<Binding> &bindings, const QString &context,
    87                         const QString &contextParent, int bindlevel);
     91    void    ChangeView(void);
     92    void    SetListContents(UIListBtnType *uilist,
     93                            const QStringList & contents,
     94                            bool arrows = false);
     95    void    UpdateRightList(void);
    8896
    8997    // Gets
    90     BindingList *GetKeyBindings(const QString &context);
    9198    uint         GetCurrentButton(void) const;
    9299
    93100    // Functions
     
    99106    void DeleteKey(void);
    100107    void LeftSelected(UIListBtnTypeItem *item);
    101108    void RightSelected(UIListBtnTypeItem *item);
    102     void SortKeyList(QStringList &keys);
    103     void RefreshKeyBindings(void);
    104109    bool JumpTo(QKeyEvent *e);
    105110    /// \brief Save the bindings to the Database.
    106111    void Save(void) { m_bindings->CommitChanges(); }
    107112
    108113  private:
     114    ViewType           m_currentView;
    109115    UIType            *m_focusedUIElement;
    110116    UIListBtnType     *m_leftList;
    111117    UIListBtnType     *m_rightList;
     
    117123    KeyBindings       *m_bindings;
    118124    LayerSet          *m_container;
    119125    QStringList        m_sortedContexts; ///< sorted list of contexts
    120     QStringList        m_sortedKeys;     ///< sorted list of keys
    121126    QDict<QStringList> m_contexts;       ///< actions for a given context
    122     QDict<BindingList> m_contextToBindingsMap;
    123     QDict<BindingList> m_keyToBindingsMap;
    124127    ListType           m_leftListType;
    125128    ListType           m_rightListType;
    126129};
  • mythcontrols/keybindings.h

     
    5959    void        CommitChanges(void);
    6060
    6161    // Gets
     62    QStringList GetKeys(void) const;
    6263    QStringList GetContexts(void) const;
    6364    QStringList GetActions(const QString &context) const;
    6465    void        GetKeyActions(const QString &key, ActionList &list) const;
    6566    QStringList GetActionKeys(const QString &context_name,
    6667                              const QString &action_name) const;
     68    QStringList GetContextKeys(const QString &context) const;
     69    QStringList GetKeyContexts(const QString &key) const;
    6770    QString     GetActionDescription(const QString &context_name,
    6871                                     const QString &action_name) const;
    6972    bool        HasMandatoryBindings(void) const;
  • mythcontrols/controls-ui.xml

     
    4646  <container name="controls">
    4747   <area>20,20,780,450</area>
    4848
    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 
    5549   <textarea name="leftdesc" draworder="1" align="center">
    5650    <font>info</font>
    57     <area>0,40,370,20</area>
     51    <area>0,0,370,20</area>
    5852    <value>Contexts</value>
    5953   </textarea>
    6054
    6155   <listbtnarea name="leftlist" draworder="0">
    62     <area>0,60,370,380</area>
     56    <area>0,30,370,420</area>
    6357    <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
    6458    <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
    6559    <fcnfont name="active" function="active"/>
     
    6963
    7064   <textarea name="rightdesc" draworder="1" align="center">
    7165    <font>info</font>
    72     <area>390,40,370,20</area>
     66    <area>390,0,370,20</area>
    7367    <value>Actions</value>
    7468   </textarea>
    7569
    7670   <listbtnarea name="rightlist" draworder="0">
    77     <area>390,60,370,380</area>
     71    <area>390,30,370,420</area>
    7872    <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
    7973    <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
    8074    <fcnfont name="active" function="active"/>
  • mythcontrols/keygrabber.cpp

     
    126126{
    127127    addLabel(tr("Options"), Large, false);
    128128    addButton(QObject::tr("Save"),   this, SLOT(Save()));
     129    addButton(QObject::tr("Change View"), this, SLOT(ChangeView()));
    129130    addButton(QObject::tr("Cancel"), this, SLOT(Cancel()))->setFocus();
    130131}
    131132