Index: mythcontrols/actionset.h
===================================================================
--- mythcontrols/actionset.h	(revision 12770)
+++ mythcontrols/actionset.h	(working copy)
@@ -58,6 +58,8 @@
     QStringList GetActionStrings(const QString &context_name) const;
     QString     GetKeyString(const ActionID &id) const;
     QStringList GetKeys(const ActionID &id) const;
+    QStringList GetContextKeys(const QString &context_name) const;
+    QStringList GetAllKeys(void) const;
     QString     GetDescription(const ActionID &id) const;
     const ActionList& GetActions(const QString &key) const;
     /// \brief Returns the appropriate container of modified actions
Index: mythcontrols/keygrabber.h
===================================================================
--- mythcontrols/keygrabber.h	(revision 12770)
+++ mythcontrols/keygrabber.h	(working copy)
@@ -94,7 +94,7 @@
     Q_OBJECT
 
   public:
-    enum actions { kSave, kCancel, };
+    enum actions { kSave, kChangeView, kCancel, };
 
     /// \brief Create a new action window. Does not pop-up menu.
     OptionsMenu(MythMainWindow *window);
@@ -103,8 +103,9 @@
     int GetOption(void) { return ExecPopup(this,SLOT(Cancel())); }
 
   public slots:
-    void Save(void)     { done(OptionsMenu::kSave);   }
-    void Cancel(void)   { done(OptionsMenu::kCancel); }
+    void Save(void)       { done(OptionsMenu::kSave);       }
+    void ChangeView(void) { done(OptionsMenu::kChangeView); }
+    void Cancel(void)     { done(OptionsMenu::kCancel);     }
 };
 
 
Index: mythcontrols/mythcontrols.cpp
===================================================================
--- mythcontrols/mythcontrols.cpp	(revision 12770)
+++ mythcontrols/mythcontrols.cpp	(working copy)
@@ -2,7 +2,7 @@
 /**
  * @file mythcontrols.cpp
  * @author Micah F. Galizia <mfgalizi@csd.uwo.ca>
- * @brief Main header for mythcontrols.
+ * @brief Main mythcontrols class.
  *
  * Note that the keybindings are fetched all at once, and cached for
  * this host.  This avoids pelting the database everytime the user
@@ -40,11 +40,11 @@
 #include "mythcontrols.h"
 #include "keygrabber.h"
 
-static QString key_to_display(const QString &key);
-static QString display_to_key(const QString &key);
-
 #define LOC QString("MythControls: ")
 #define LOC_ERR QString("MythControls, Error: ")
+#define CAPTION_CONTEXT QString("Contexts")
+#define CAPTION_ACTION QString("Actions")
+#define CAPTION_KEY QString("Keys")
 
 /** \fn MythControls::MythControls(MythMainWindow*, bool&)
  *  \brief Creates a new MythControls wizard
@@ -53,6 +53,7 @@
  */
 MythControls::MythControls(MythMainWindow *parent, bool &ok)
     : MythThemedDialog(parent, "controls", "controls-", "controls"),
+      m_currentView(kActionsByContext),
       m_focusedUIElement(NULL),
       m_leftList(NULL),        m_rightList(NULL),
       m_description(NULL),
@@ -71,8 +72,12 @@
     m_rightListType = kActionList;
 
     LoadData(gContext->GetHostName());
-    RefreshKeyInformation();
 
+    /* start off with the actions by contexts view */
+    m_currentView = kActionsByContext;
+    SetListContents(m_leftList, m_bindings->GetContexts(), true);
+    UpdateRightList();
+
     connect(m_leftList,  SIGNAL(itemSelected( UIListBtnTypeItem*)),
             this,        SLOT(  LeftSelected( UIListBtnTypeItem*)));
     connect(m_rightList, SIGNAL(itemSelected( UIListBtnTypeItem*)),
@@ -221,6 +226,52 @@
     RefreshKeyInformation();
 }
 
+/// \brief Chagne the view.
+void MythControls::ChangeView(void)
+{
+    ViewMenu popup(gContext->GetMainWindow());
+    QStringList contents;
+    QString leftcaption, rightcaption;
+
+    switch(popup.GetOption())
+    {
+        case ViewMenu::kContextAction:
+            leftcaption = tr(CAPTION_CONTEXT);
+            rightcaption = tr(CAPTION_ACTION);
+            m_currentView = kActionsByContext;
+            contents = m_bindings->GetContexts();
+            break;
+        case ViewMenu::kContextKey:
+            leftcaption = tr(CAPTION_CONTEXT);
+            rightcaption = tr(CAPTION_KEY);
+            m_currentView = kKeysByContext;
+            contents = m_bindings->GetContexts();
+            break;
+        case ViewMenu::kKeyContext:
+            leftcaption = tr(CAPTION_KEY);
+            rightcaption = tr(CAPTION_CONTEXT);
+            m_currentView = kContextsByKey;
+            contents = m_bindings->GetKeys();
+            break;
+        default:
+            break;
+    }
+
+    m_leftDescription->SetText(leftcaption);
+    m_rightDescription->SetText(rightcaption);
+
+    SetListContents(m_leftList, contents, true);
+    RefreshKeyInformation();
+    UpdateRightList();
+
+    if (m_focusedUIElement != m_leftList)
+    {
+        m_focusedUIElement->looseFocus();
+        m_focusedUIElement = m_leftList;
+        m_focusedUIElement->takeFocus();
+    }
+}
+
 void MythControls::keyPressEvent(QKeyEvent *e)
 {
     bool handled = false;
@@ -238,9 +289,19 @@
             m_focusedUIElement->looseFocus();
 
             OptionsMenu popup(gContext->GetMainWindow());
-            if (OptionsMenu::kSave == popup.GetOption())
-                Save();
 
+            switch(popup.GetOption())
+            {
+                case OptionsMenu::kSave:
+                    Save();
+                    break;
+                case OptionsMenu::kChangeView:
+                    ChangeView();
+                    break;
+                default:
+                    break;
+            }
+
             m_focusedUIElement->takeFocus();
         }
         else if (action == "SELECT")
@@ -248,7 +309,12 @@
             if (m_focusedUIElement == m_leftList)
                 ChangeListFocus(m_rightList, m_leftList);
             else if (m_focusedUIElement == m_rightList)
-                ChangeButtonFocus(0);
+            {
+                if (m_currentView == kActionsByContext)
+                    ChangeButtonFocus(0);
+                else
+                    handled = false;
+            }
             else
             {
                 QString key = GetCurrentKey();
@@ -327,69 +393,6 @@
             else if (m_focusedUIElement == m_rightList)
                 m_rightList->MoveDown(UIListBtnType::MovePage);
         }
-        else if (action == "1")
-        {
-            if ((m_leftListType  != kContextList) ||
-                (m_rightListType != kActionList))
-            {
-                m_leftListType  = kContextList;
-                m_rightListType = kActionList;
-                UpdateLists();
-
-                if (m_focusedUIElement != m_leftList)
-                {
-                    ChangeListFocus(m_leftList,
-                                    (m_focusedUIElement == m_rightList) ?
-                                    m_rightList : NULL);
-                }
-            }
-            else
-            {
-                handled = false;
-            }
-        }
-        else if (action == "2")
-        {
-            if ((m_leftListType  != kContextList) ||
-                (m_rightListType != kKeyList))
-            {
-                m_leftListType  = kContextList;
-                m_rightListType = kKeyList;
-                UpdateLists();
-
-                if (m_focusedUIElement != m_leftList)
-                {
-                    ChangeListFocus(m_leftList,
-                                    (m_focusedUIElement == m_rightList) ?
-                                    m_rightList : NULL);
-                }
-            }
-            else
-            {
-                handled = false;
-            }
-        }
-        else if (action == "3")
-        {
-            if ((m_leftListType  != kKeyList) ||
-                (m_rightListType != kContextList))
-            {
-                m_leftListType  = kKeyList;
-                m_rightListType = kContextList;
-                UpdateLists();
-
-                if (m_focusedUIElement != m_leftList)
-                {
-                    ChangeListFocus(m_leftList,
-                                    (m_focusedUIElement == m_rightList) ?
-                                    m_rightList : NULL);
-                }
-            }
-            else
-            {
-                handled = false;
-            }
-        }
         else
         {
             handled = false;
@@ -397,83 +400,9 @@
     }
 
     if (!handled)
-    {
-        handled |= (!escape && JumpTo(e));
-        if (!handled)
-            MythThemedDialog::keyPressEvent(e);
-    }
+        MythThemedDialog::keyPressEvent(e);
 }
 
-/** \fn MythControls::JumpTo(QKeyEvent*)
- *  \brief Jump to a particular key binding
- *  \param e key event to use as jump
- */
-bool MythControls::JumpTo(QKeyEvent *e)
-{
-    UIListBtnType *list = NULL;
-
-    list = ((m_focusedUIElement == m_leftList) &&
-            (m_leftListType     == kKeyList)) ? m_leftList  : list;
-    list = ((m_focusedUIElement == m_rightList) &&
-            (m_rightListType    == kKeyList)) ? m_rightList : list;
-
-    if (!list)
-        return false;
-
-    QString key = e->text();
-    if (key.left(6) == "remote")
-    {
-        key = key_to_display(key);
-    }
-    else
-    {
-        key = QString(QKeySequence(e->key()));
-
-        if (key.isEmpty())
-            return false;
-
-        QString modifiers = "";
-
-        if (e->state() & Qt::ShiftButton)
-            modifiers += "Shift+";
-        if (e->state() & Qt::ControlButton)
-            modifiers += "Ctrl+";
-        if (e->state() & Qt::AltButton)
-            modifiers += "Alt+";
-        if (e->state() & Qt::MetaButton)
-            modifiers += "Meta+";
-
-        key = modifiers + key;
-    }
-
-    uint len = 1024; // infinity
-    if (list == m_rightList)
-    {
-        key = key + " ";
-        len = key.length();
-    }
-
-    UIListBtnTypeItem *b;
-    for (b = list->GetItemFirst(); b; b = list->GetItemNext(b))
-    {
-        if (b->text().left(len) == key)
-            break;
-    }
-
-    if (!b)
-        return false;
-
-    int curpos = list->GetItemPos(list->GetItemCurrent());
-    int newpos = list->GetItemPos(b);
-
-    if (newpos > curpos)
-        list->MoveDown(newpos - curpos);
-    else if (newpos < curpos)
-        list->MoveUp(curpos - newpos);
-
-    return true;
-}
-
 /** \fn MythControls::LeftSelected(UIListBtnTypeItem*)
  *  \brief Refreshes the right list when an item in the
  *         left list is selected
@@ -482,7 +411,7 @@
 {
     m_leftList->refresh();
     m_rightList->blockSignals(true);
-    RefreshRightList();
+    UpdateRightList();
     m_rightList->blockSignals(false);
     m_rightList->refresh();
 }
@@ -497,166 +426,56 @@
     RefreshKeyInformation();
 }
 
-/** \fn MythControls::RefreshRightList(void)
- *  \brief Load the appropriate actions into the action list
+
+/** \brief Set the contents of a list.
+ *  \param list The list being changed.
+ *  \param contents The contents of the list.
+ *  \param arrows True to draw with arrows, otherwise arrows are not drawn.
  */
-void MythControls::RefreshRightList(void)
+void MythControls::SetListContents(
+    UIListBtnType *uilist, const QStringList &contents, bool arrows)
 {
-    m_rightList->Reset();
+    uilist->blockSignals(true);
 
-    if (!m_leftList->GetItemCurrent())
-        return;
+    // remove all strings from the current list
+    uilist->Reset();
 
-    if (m_leftListType == kContextList)
+    // add each new string
+    for (size_t i = 0; i < contents.size(); i++)
     {
-        if (m_rightListType == kActionList)
-        {
-            /* add all of the actions to the context list */
-            QString context = m_leftList->GetItemCurrent()->text();
-            QStringList *actions = m_contexts[context];
-            if (!actions || actions->empty())
-            {
-                VERBOSE(VB_IMPORTANT, LOC_ERR + 
-                        QString("Unable to find actions for context %1")
-                        .arg(context));
-
-                return;
-            }
-
-            for (uint i = 0; i < actions->size(); i++)
-                new UIListBtnTypeItem(m_rightList, (*actions)[i]);
-        }
-        else if (m_rightListType == kKeyList)
-        {
-            /* add all of the actions to the context list */
-            QString context = m_leftList->GetItemCurrent()->text();
-            const BindingList *list = m_contextToBindingsMap[context];
-            if (!list)
-            {
-                VERBOSE(VB_IMPORTANT, LOC_ERR+ 
-                        QString("Unable to find keys for context %1")
-                        .arg(context));
-
-                return;
-            }
-
-            BindingList::const_iterator it = list->begin();
-            for (; it != list->end(); ++it)
-            {
-                new UIListBtnTypeItem(
-                    m_rightList,
-                    key_to_display((*it)->key) + " => " + (*it)->action);
-            }
-        }
+        UIListBtnTypeItem *item = new UIListBtnTypeItem(uilist, contents[i]);
+        item->setDrawArrow(arrows);
     }
-    else if ((m_leftListType == kKeyList) && (m_rightListType == kContextList))
-    {
-        QString key = display_to_key(m_leftList->GetItemCurrent()->text());
-        const BindingList *list = m_keyToBindingsMap[key];
-        if (!list)
-        {
-            VERBOSE(VB_IMPORTANT, LOC + QString(
-                        "Unable to find actions for key %1").arg(key));
-            return;
-        }
 
-        BindingList::const_iterator it = list->begin();
-        const Binding *b = *it;
-        for (uint i = 0; i < m_sortedContexts.size(); i++)
-        {
-            const QString context = m_sortedContexts[i];
-            QString action  = "<none>";
-
-            if (b && b->context == context)
-            {
-                action = b->action;
-                ++it;
-                b = (it != list->end()) ? *it : NULL;
-            }
-
-            new UIListBtnTypeItem(m_rightList, context + " => " + action);
-        }
-    }
+    uilist->blockSignals(false);
+    uilist->refresh();
 }
 
-QString MythControls::RefreshKeyInformationKeyList(void)
+/** \brief Update the right list. */
+void MythControls::UpdateRightList(void)
 {
-    if ((m_leftListType != kKeyList) && (m_rightListType != kKeyList))
-        return "";
+    // get the selected item in the right list.
+    UIListBtnTypeItem *item = m_leftList->GetItemCurrent();
 
-    QString action  = GetCurrentAction();
-    QString context = GetCurrentContext();
-
-    if (action.isEmpty())
-        return "";
-
-    QString desc = m_bindings->GetActionDescription(context, action);
-    
-    BindingList *list = NULL;
-    if (m_leftListType == kKeyList && m_rightListType == kContextList)
+    if (item != NULL)
     {
-        list = m_keyToBindingsMap[display_to_key(GetCurrentKey())];
-    }
-    else if (m_leftListType == kContextList && m_rightListType == kKeyList)
-    {
-        list = m_contextToBindingsMap[context];
-    }
+        QString rtstr = item->text();
 
-    if (!list)
-        return desc;
-
-    QString searchKey = QString::null;
-    if (m_rightListType == kContextList)
-    {
-        searchKey = context;
-    }
-    else if (m_rightListType == kActionList)
-    {
-        searchKey = action;
-    }
-    else if (m_rightListType == kKeyList)
-    {
-        searchKey = display_to_key(GetCurrentKey());
-    }
-
-    const Binding *binding = NULL;
-    for (BindingList::const_iterator it = list->begin();
-         it != list->end(); ++it)
-    {
-        switch (m_rightListType)
+        switch(m_currentView)
         {
-            case kContextList:
-                if ((*it)->context == searchKey)
-                    binding = *it;
-                break;
-            case kActionList:
-                if ((*it)->action == searchKey)
-                    binding = *it;
-                break;
-            case kKeyList:
-                if ((*it)->key == searchKey)
-                    binding = *it;
-                break;
-        }
-
-        if (binding)
+        case kActionsByContext:
+            SetListContents(m_rightList, *(m_contexts[rtstr]));
             break;
+        case kKeysByContext:
+            SetListContents(m_rightList, m_bindings->GetContextKeys(rtstr));
+            break;
+        case kContextsByKey:
+            SetListContents(m_rightList, m_bindings->GetKeyContexts(rtstr));
+            break;
+        }
     }
-    
-    if (!binding)
-        return desc;
-
-
-    if (desc.isEmpty() && (context != binding->contextFrom))
-    {
-        desc = m_bindings->GetActionDescription(
-            binding->contextFrom, action);
-    }
-
-    desc += "\n" + tr("Binding comes from %1 context")
-        .arg(binding->contextFrom);
-
-    return desc;
+    else
+        VERBOSE(VB_IMPORTANT, QString("Left List Returned Null!"));
 }
 
 /** \fn MythControls::RefreshKeyInformation(void)
@@ -674,12 +493,6 @@
         return;
     }
 
-    if ((m_leftListType == kKeyList) || (m_rightListType == kKeyList))
-    {
-        m_description->SetText(RefreshKeyInformationKeyList());
-        return;
-    }
-
     const QString context = GetCurrentContext();
     const QString action  = GetCurrentAction();
 
@@ -690,7 +503,7 @@
     for (uint i = 0; (i < keys.count()) &&
              (i < Action::kMaximumNumberOfBindings); i++)
     {
-        m_actionButtons[i]->setText(key_to_display(keys[i]));
+        m_actionButtons[i]->setText(keys[i]);
     }
 }
 
@@ -731,14 +544,21 @@
 QString MythControls::GetCurrentAction(void) const
 {
     if (m_leftListType == kActionList)
-        return m_leftList->GetItemCurrent()->text();
+    {
+        if (m_leftList && m_leftList->GetItemCurrent())
+            return QDeepCopy<QString>(m_leftList->GetItemCurrent()->text());
+        return QString::null;
+    }
 
     if (m_focusedUIElement == m_leftList)
         return QString::null;
 
+    if (!m_rightList || !m_rightList->GetItemCurrent())
+        return QString::null;
+
     QString desc = m_rightList->GetItemCurrent()->text();
     if (m_leftListType == kContextList && m_rightListType == kActionList)
-        return desc;
+        return QDeepCopy<QString>(desc);
 
     int loc = desc.find(" => ");
     if (loc == -1)
@@ -794,7 +614,7 @@
     return desc.mid(loc + 4);
 }
 
-/** \fn MythControls::LoadAll(const QString&)
+/** \fn MythControls::LoadData(const QString&)
  *  \brief Load the settings for a particular host.
  *  \param hostname The host to load settings for.
  */
@@ -804,8 +624,6 @@
     m_bindings = new KeyBindings(hostname);
     m_sortedContexts = m_bindings->GetContexts();
 
-    m_sortedKeys.clear();
-
     /* Alphabetic order, but jump and global at the top  */
     m_sortedContexts.sort();
     m_sortedContexts.remove(ActionSet::kJumpContext);
@@ -822,9 +640,6 @@
         actions.sort();
         m_contexts.insert(m_sortedContexts[i], new QStringList(actions));
     }
-
-    RefreshKeyBindings();
-    UpdateLists();
 }
 
 /** \fn MythControls::DeleteKey(void)
@@ -846,49 +661,18 @@
         return;
     }
 
-    BindingList *list = m_keyToBindingsMap[key];
-    Binding *binding = NULL;
+    ConfirmMenu popup(gContext->GetMainWindow(), tr("Delete this binding?"));
 
-    for (BindingList::iterator it = list->begin(); it != list->end(); ++it)
-    {
-        Binding *b = *it;
-        if (b->context == context)
-            binding = b;
-    }
-
-    if (!binding)
-    {
-        InvalidBindingPopup popup(gContext->GetMainWindow());
-        popup.GetOption();
+    if (popup.GetOption() != ConfirmMenu::kConfirm)
         return;
-    }
 
-    if (binding->contextFrom != context)
+    if (!m_bindings->RemoveActionKey(context, action, key))
     {
-        ConfirmMenu popup(gContext->GetMainWindow(),
-                          tr("Delete this key binding from context %1?")
-                          .arg(binding->contextFrom));
-
-        if (popup.GetOption() != ConfirmMenu::kConfirm)
-            return;
-    }
-    else
-    {
-        ConfirmMenu popup(gContext->GetMainWindow(),
-                          tr("Delete this binding?"));
-
-        if (popup.GetOption() != ConfirmMenu::kConfirm)
-            return;
-    }
-
-    if (!m_bindings->RemoveActionKey(binding->contextFrom, action, key))
-    {
         InvalidBindingPopup popup(gContext->GetMainWindow());
         popup.GetOption();
         return;
     }
 
-    RefreshKeyBindings();
     RefreshKeyInformation();
 }
 
@@ -977,231 +761,21 @@
         m_bindings->AddActionKey(context, action, key);
     }
 
-    RefreshKeyBindings();
     RefreshKeyInformation();
 }
 
-/** \fn MythControls::AddBindings(QDict<Binding>&, const QString&,
-                                  const QString&, int)
- *  \brief Add bindings to QDict<Binding> for specified context
- *  \param bindings the QDict to which to add the bindings
- *  \param context the context to grab keybindings from
- *  \param contextParent the context whose keybindings are being calculated
- *  \param bindlevel the bind level associated with this context
+/** \fn ViewMenu::ViewMenu(MythMainWindow*, ViewType)
+ *  \brief Creates a new view dialog box.
+ *  \param window The main MythTV window.
  */
-void MythControls::AddBindings(QDict<Binding> &bindings,
-                               const QString    &context,
-                               const QString    &contextParent,
-                               int               bindlevel)
+ViewMenu::ViewMenu(MythMainWindow *window) :
+    MythPopupBox(window, "mcviewmenu")
 {
-    QStringList actions = m_bindings->GetActions(context);
-
-    for (uint i = 0; i < actions.size(); i++)
-    {
-        QString action = actions[i];
-        QStringList keys = m_bindings->GetActionKeys(context, action);
-
-        for (uint j = 0; j < keys.size(); j++)
-        {
-            Binding *b = bindings.find(keys[j]);
-
-            if (!b) 
-            {
-                b = new Binding(keys[j], contextParent,
-                                context, action, bindlevel);
-
-                bindings.insert(keys[j], b);
-            }
-            else if (b->bindlevel == bindlevel)
-            {
-                b->action += ", " + action;
-            }
-        }
-    }
+    addLabel(tr("Change View"), Large, false);
+    addButton(tr("Actions By Context"), this, SLOT(ActionsByContext()));
+    addButton(tr("Contexts By Key"), this, SLOT(ContextsByKey()));
+    addButton(tr("Keys By Context"), this, SLOT(KeysByContext()));
+    addButton(tr("Cancel"), this, SLOT(Cancel()))->setFocus();
 }
 
-/** \fn MythControls::GetKeyBindings(const QString&)
- *  \brief Create a BindingList for the specified context
- *  \param context the context for which a BindingList should be created
- *  \return a BindingList with "auto delete" property enabled.
- */
-BindingList *MythControls::GetKeyBindings(const QString &context)
-{
-    QDict<Binding> bindings;
-    for (uint i = 0; i < m_sortedContexts.size(); i++)
-        AddBindings(bindings, m_sortedContexts[i], context, i);
-
-    QStringList keys;
-    for (QDictIterator<Binding> it(bindings); it.current(); ++it)
-        keys.append(it.currentKey());
-
-    SortKeyList(keys);
-
-    BindingList *blist = new BindingList();
-    blist->setAutoDelete(true);
-
-    QStringList::const_iterator kit = keys.begin();
-    for (; kit != keys.end(); ++kit)
-        blist->append(bindings[*kit]);
-
-    return blist;
-}
-
-/** \fn MythControls::RefreshKeyBindings(void)
- *  \brief Refresh binding information
- */
-void MythControls::RefreshKeyBindings(void)
-{
-    m_contextToBindingsMap.clear();
-    m_keyToBindingsMap.clear();
-    m_contextToBindingsMap.setAutoDelete(true);
-    m_keyToBindingsMap.setAutoDelete(true);
-
-    for (uint i = 0; i < m_sortedContexts.size(); i++)
-    {
-        QString context = m_sortedContexts[i];
-        BindingList *list = GetKeyBindings(context);
-        m_contextToBindingsMap.insert(context, list);
-
-        BindingList::const_iterator it = list->begin();
-        for (; it != list->end(); ++it)
-        {
-            BindingList *list = m_keyToBindingsMap.find((*it)->key);
-
-            if (!list)
-            {
-                list = new BindingList();
-                m_keyToBindingsMap.insert((*it)->key, list);
-            }
-
-            m_sortedKeys.append((*it)->key);
-            list->append(*it);
-        }
-    }
-
-    SortKeyList(m_sortedKeys);
-}
-
-/** \fn MythControls::SortKeyList(QStringList&)
- *  \brief Sort a list of keys, removing duplicates
- *  \param keys the list of keys to sort
- */
-void MythControls::SortKeyList(QStringList &keys)
-{
-    QStringList tmp;
-    QStringList::const_iterator it = keys.begin();
-    for (; it != keys.end(); ++it)
-    {
-        QString key     = *it;
-        QString keydesc = (key.left(6) == "remote") ? "0 " : "3 ";
-
-        keydesc = ((key.length() > 1) && !(key.left(6) == "remote") &&
-                   (key.find("+", 1) >= 0)) ? "4 " : keydesc;
-
-        if (key.length() == 1)
-        {
-            QChar::Category cat = key[0].category();
-            keydesc = (QChar::Letter_Uppercase    == cat) ? "2 " : "5 ";
-            keydesc = (QChar::Number_DecimalDigit == cat) ? "1 " : keydesc;
-        }
-
-        tmp.push_back(keydesc + key);
-    }
-    tmp.sort();
-
-    keys.clear();
-
-    QString prev = QString::null;
-    for (it = tmp.begin(); it != tmp.end(); ++it)
-    {
-        QString cur = (*it).mid(2);
-        if (cur != prev)
-        {
-            keys.append(cur);
-            prev = cur;
-        }
-    }
-}
-
-/// NOTE: This can not be a static method because the QObject::tr()
-///       translations do not work reliably in static initializers.
-QString MythControls::GetTypeDesc(ListType type) const
-{
-    switch (type)
-    {
-        case kContextList:
-            return tr("Contexts");
-            break;
-        case kKeyList:
-            return tr("Keys");
-            break;
-        case kActionList:
-            return tr("Actions");
-            break;
-        default:
-            return "";
-    }
-}
-
-/** \fn MythControls::UpdateLists(void)
- *  \brief Redisplays both the left and right lists and fixes focus issues.
- */
-void MythControls::UpdateLists(void)
-{
-    m_rightList->blockSignals(true);
-    m_leftList->blockSignals(true);
-    m_leftList->Reset();
-
-    if (m_leftListType == kContextList)
-    {
-        for (uint i = 0; i < m_sortedContexts.size(); i++)
-        {
-            UIListBtnTypeItem *item = new UIListBtnTypeItem(
-                m_leftList, m_sortedContexts[i]);
-
-            item->setDrawArrow(true);
-        }
-    }
-    else if (m_leftListType == kKeyList)
-    {
-        for (uint i = 0; i < m_sortedKeys.size(); i++)
-        {
-            UIListBtnTypeItem *item = new UIListBtnTypeItem(
-                m_leftList, key_to_display(m_sortedKeys[i]));
-
-            item->setDrawArrow(true);
-        }
-    }
-
-    RefreshRightList();
-
-    m_rightList->blockSignals(false);
-    m_leftList->blockSignals(false);
-
-    m_leftList->refresh();
-    m_rightList->refresh();
-
-    if (m_leftDescription)
-        m_leftDescription->SetText(GetTypeDesc(m_leftListType));
-
-    if (m_rightDescription)
-        m_rightDescription->SetText(GetTypeDesc(m_rightListType));
-}
-
-static QString key_to_display(const QString &key)
-{
-    if (key.left(6) == "remote")
-        return "[" + key.mid(6) + "]";
-
-    return key;
-}
-
-static QString display_to_key(const QString &key)
-{
-    if (key.left(1) == "[" && key != "[")
-        return "remote" + key.mid(1, key.length() - 2);
-
-    return key;
-}
-
 /* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: mythcontrols/keybindings.cpp
===================================================================
--- mythcontrols/keybindings.cpp	(revision 12770)
+++ mythcontrols/keybindings.cpp	(working copy)
@@ -49,13 +49,22 @@
     LoadJumppoints();
 }
 
+/** \brief Returns a list of all keys bound to an action. */
+QStringList KeyBindings::GetKeys(void) const
+{
+    return m_actionSet.GetAllKeys();
+}
+
 /** \fn KeyBindings::GetContexts(void) const
  *  \brief Returns a list of the context names.
  *  \note The returned list is a copy and can be modified without side-effects.
  */
 QStringList KeyBindings::GetContexts(void) const
 {
-    return QDeepCopy<QStringList>(m_actionSet.GetContextStrings());
+    QStringList ctxts = 
+        QDeepCopy<QStringList>(m_actionSet.GetContextStrings());
+    ctxts.sort();
+    return ctxts;
 }
 
 /** \fn KeyBindings::GetActions(const QString&) const
@@ -95,6 +104,35 @@
         (m_actionSet.GetKeys(ActionID(context_name, action_name)));
 }
 
+/** \fn KeyBindings::GetContextKeys(const QString &) const
+ *  \brief Get the keys within a context.
+ *  \param context The context name.
+ *  \return A list of the keys in the context.
+ */
+QStringList KeyBindings::GetContextKeys(const QString &context) const
+{
+    return m_actionSet.GetContextKeys(context);
+}
+
+/** \fn KeyBindings::GetKeyContexts(const QString &) const
+ *  \brief Get the context names in which a key is bound.
+ *  \return A list of context names in which a key is bound.
+ */
+QStringList KeyBindings::GetKeyContexts(const QString &key) const
+{
+    ActionList actions = m_actionSet.GetActions(key);
+    QStringList contexts;
+
+    for (size_t i = 0; i < actions.size(); i++)
+    {
+        QString context = actions[i].GetContext();
+        if (!contexts.contains(context))
+            contexts.push_back(context);
+    }
+
+    return contexts;
+}
+
 /** \fn KeyBindings::GetActionDescription(const QString&,const QString&) const
  *  \brief Get an action's description.
  *  \param context_name The name of the context.
Index: mythcontrols/actionset.cpp
===================================================================
--- mythcontrols/actionset.cpp	(revision 12770)
+++ mythcontrols/actionset.cpp	(working copy)
@@ -62,7 +62,7 @@
 
     ActionList &ids = m_keyToActionMap[key];
     ids.push_back(id);
-    SetModifiedFlag(id, true);	
+    SetModifiedFlag(id, true);
 
     return true;
 }
@@ -75,6 +75,9 @@
  *
  *  \param id The action identifier to remove from.
  *  \param key The key to remove.
+ *
+ *  \todo Remove the actionlist from the m_keyToActionMap if the key
+ *        is no longer bound to any actions.
  */
 bool ActionSet::Remove(const ActionID &id, const QString &key)
 {
@@ -87,9 +90,14 @@
         return false;
 
     m_keyToActionMap[key].remove(id);
+
+    // remove the key if there isn't anything bound to it.
+    if (m_keyToActionMap[key].isEmpty())
+        m_keyToActionMap.remove(key);
+
     SetModifiedFlag(id, true);
 
-    return true;	    
+    return true;
 }
 
 /** \fn ActionSet::Replace(const ActionID&,const QString&,const QString&)
@@ -118,7 +126,7 @@
     m_keyToActionMap[newkey].push_back(id);
     SetModifiedFlag(id, true);
 
-    return true;	    
+    return true;
 }
 
 /** \fn ActionSet::SetModifiedFlag(const ActionID&, bool)
@@ -242,6 +250,39 @@
     return keys;
 }
 
+QStringList ActionSet::GetContextKeys(const QString & context_name) const
+{
+    QStringList keys;
+    Context *c = m_contexts[context_name];
+
+    QDictIterator<Action> it(*c);
+    for (;it.current(); ++it)
+    {
+        QStringList akeys = (*it)->GetKeys();
+        for (size_t i = 0; i < akeys.size(); i++)
+        {
+                keys.append(akeys[i]);
+        }
+        keys.sort();
+    }
+
+    return keys;
+}
+
+/** \brief Get all keys (from every context) to which an action is bound.
+ */
+QStringList ActionSet::GetAllKeys(void) const
+{
+    QStringList keys;
+
+    QMap<QString, ActionList>::ConstIterator it;
+
+    for (it = m_keyToActionMap.begin(); it != m_keyToActionMap.end(); ++it)
+        keys.push_back(it.key());
+
+    return keys;
+}
+
 /** \fn ActionSet::GetDescription(const ActionID&) const
  *  \brief Returns the description of an action by its identifier.
  *         (note: result not thread-safe)
Index: mythcontrols/mythcontrols.h
===================================================================
--- mythcontrols/mythcontrols.h	(revision 12770)
+++ mythcontrols/mythcontrols.h	(working copy)
@@ -29,23 +29,31 @@
 
 #include "keybindings.h"
 
-class Binding
+
+typedef enum { kActionsByContext, kKeysByContext, kContextsByKey, } ViewType;
+
+/** \class ViewMenu
+ *  \brief Prompts the user to change the view.
+ */
+class ViewMenu : public MythPopupBox
 {
+    Q_OBJECT
+
   public:
-    Binding(const QString &_key,         const QString &_context,
-            const QString &_contextFrom, const QString &_action,
-            int            _bindlevel) :
-        key(_key), context(_context),
-        contextFrom(_contextFrom), action(_action), bindlevel(_bindlevel) {}
+    ViewMenu(MythMainWindow *window);
 
-  public:
-    QString key;
-    QString context;
-    QString contextFrom;
-    QString action;
-    int     bindlevel;
+    /// \brief Execute the option popup.
+    int GetOption(void) { return ExecPopup(this, SLOT(Cancel())); }
+
+    /// \brief The available views
+    enum actions { kContextAction, kContextKey, kKeyContext, kCancel, };
+
+  public slots:
+    void ActionsByContext(void) { done(ViewMenu::kContextAction); }
+    void KeysByContext(void)    { done(ViewMenu::kContextKey);    }
+    void ContextsByKey(void)    { done(ViewMenu::kKeyContext);    }
+    void Cancel(void)           { done(ViewMenu::kCancel);        }
 };
-typedef QPtrList<Binding> BindingList;
 
 /** \class MythControls
  *  \brief The myth controls configuration class.
@@ -77,17 +85,16 @@
     // Commands
     bool    LoadUI(void);
     void    RefreshKeyInformation(void);
-    QString RefreshKeyInformationKeyList(void);
-    void    RefreshRightList(void);
-    void    UpdateLists(void);
     void    LoadData(const QString &hostname);
     void    ChangeButtonFocus(int direction);
     void    ChangeListFocus(UIListBtnType *focus, UIListBtnType *unfocus);
-    void    AddBindings(QDict<Binding> &bindings, const QString &context,
-                        const QString &contextParent, int bindlevel);
+    void    ChangeView(void);
+    void    SetListContents(UIListBtnType *uilist,
+                            const QStringList & contents,
+                            bool arrows = false);
+    void    UpdateRightList(void);
 
     // Gets
-    BindingList *GetKeyBindings(const QString &context);
     uint         GetCurrentButton(void) const;
 
     // Functions
@@ -99,13 +106,12 @@
     void DeleteKey(void);
     void LeftSelected(UIListBtnTypeItem *item);
     void RightSelected(UIListBtnTypeItem *item);
-    void SortKeyList(QStringList &keys);
-    void RefreshKeyBindings(void);
     bool JumpTo(QKeyEvent *e);
     /// \brief Save the bindings to the Database.
     void Save(void) { m_bindings->CommitChanges(); }
 
   private:
+    ViewType           m_currentView;
     UIType            *m_focusedUIElement;
     UIListBtnType     *m_leftList;
     UIListBtnType     *m_rightList;
@@ -117,10 +123,7 @@
     KeyBindings       *m_bindings;
     LayerSet          *m_container;
     QStringList        m_sortedContexts; ///< sorted list of contexts
-    QStringList        m_sortedKeys;     ///< sorted list of keys
     QDict<QStringList> m_contexts;       ///< actions for a given context
-    QDict<BindingList> m_contextToBindingsMap;
-    QDict<BindingList> m_keyToBindingsMap;
     ListType           m_leftListType;
     ListType           m_rightListType;
 };
Index: mythcontrols/keybindings.h
===================================================================
--- mythcontrols/keybindings.h	(revision 12770)
+++ mythcontrols/keybindings.h	(working copy)
@@ -59,11 +59,14 @@
     void        CommitChanges(void);
 
     // Gets
+    QStringList GetKeys(void) const;
     QStringList GetContexts(void) const;
     QStringList GetActions(const QString &context) const;
     void        GetKeyActions(const QString &key, ActionList &list) const;
     QStringList GetActionKeys(const QString &context_name,
                               const QString &action_name) const;
+    QStringList GetContextKeys(const QString &context) const;
+    QStringList GetKeyContexts(const QString &key) const;
     QString     GetActionDescription(const QString &context_name,
                                      const QString &action_name) const;
     bool        HasMandatoryBindings(void) const;
Index: mythcontrols/controls-ui.xml
===================================================================
--- mythcontrols/controls-ui.xml	(revision 12770)
+++ mythcontrols/controls-ui.xml	(working copy)
@@ -46,20 +46,14 @@
   <container name="controls">
    <area>20,20,780,450</area>
 
-   <textarea name="options" draworder="1" align="center">
-    <font>options</font>
-    <area>0,0,780,30</area>
-    <value>(1) Contexts / Actions  (2) Contexts / Keys  (3) Keys / Contexts</value>
-   </textarea>
-
    <textarea name="leftdesc" draworder="1" align="center">
     <font>info</font>
-    <area>0,40,370,20</area>
+    <area>0,0,370,20</area>
     <value>Contexts</value>
    </textarea>
 
    <listbtnarea name="leftlist" draworder="0">
-    <area>0,60,370,380</area>
+    <area>0,30,370,420</area>
     <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
     <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
     <fcnfont name="active" function="active"/>
@@ -69,12 +63,12 @@
 
    <textarea name="rightdesc" draworder="1" align="center">
     <font>info</font>
-    <area>390,40,370,20</area>
+    <area>390,0,370,20</area>
     <value>Actions</value>
    </textarea>
 
    <listbtnarea name="rightlist" draworder="0">
-    <area>390,60,370,380</area>
+    <area>390,30,370,420</area>
     <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
     <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
     <fcnfont name="active" function="active"/>
Index: mythcontrols/keygrabber.cpp
===================================================================
--- mythcontrols/keygrabber.cpp	(revision 12770)
+++ mythcontrols/keygrabber.cpp	(working copy)
@@ -126,6 +126,7 @@
 {
     addLabel(tr("Options"), Large, false);
     addButton(QObject::tr("Save"),   this, SLOT(Save()));
+    addButton(QObject::tr("Change View"), this, SLOT(ChangeView()));
     addButton(QObject::tr("Cancel"), this, SLOT(Cancel()))->setFocus();
 }
     
