Ticket #98: ListUI_And_Sorting.diff

File ListUI_And_Sorting.diff, 40.6 KB (added by mfgalizi@…, 16 years ago)

This one is the same as the previous, but the UI doesn't use the managed tree list. Now it uses a nice UILIstTreeType.

  • mythcontrols/mythcontrols/mythcontrols.cpp

     
    3636
    3737/* MythTV includes */
    3838#include <mythtv/mythcontext.h>
    39 #include <mythtv/uitypes.h>
    4039#include <mythtv/mythdialogs.h>
    41 #include <mythtv/dialogbox.h>
    42 #include <mythtv/xmlparse.h>
    4340#include <mythtv/themedmenu.h>
    44 #include <mythtv/mythdbcon.h>
    4541
    4642using namespace std;
    4743
    4844#include "mythcontrols.h"
    4945#include "keygrabber.h"
    5046
    51 /**
    52  * @class ConflictResolver
    53  * @brief A MythDialog that notifies the user of conflicts.
    54  */
    55 class ConflictResolver : public MythPopupBox
    56 {
    5747
    58 public:
    59     ConflictResolver(MythMainWindow *window, ActionID *conflict)
    60         : MythPopupBox(window, "conflictresolver")
    61     {
    62         QString warning = "The key you have chosen is already bound to "
    63             + conflict->action() + " in the " + conflict->context()
    64             + " context; please rebind it before binding this key.";
    65        
    66         addLabel("Action Conflict", Large, false);
    67         addLabel(warning, Small, true);
    68     }
    6948
    70 
    71     ConflictResolver(MythMainWindow *window)
    72         : MythPopupBox(window,"conflictresolver")
    73     {
    74 
    75         QString warning;
    76         warning = "This action is manditory and needs at least one key bound ";
    77         warning += "to it.  Instead, try rebinding with another key.";
    78            
    79         addLabel("Manditory Action", Large, false);
    80         addLabel(warning, Small, true);
    81     }
    82 };
    83 
    84 
    8549/* comments in header */
    86 MythControls::MythControls (MythMainWindow *parent, const char *name)
     50MythControls::MythControls (MythMainWindow *parent, const char *name,
     51                            bool & ui_ok)
    8752    :MythThemedDialog(parent, "controls", "controls-", name)
    8853{
     54    /* Nullify keybindings so the deconstructor knows not to delete it */
     55    this->key_bindings = NULL;
     56
    8957    /* load up the ui components */
    90     loadUI();
     58    if ((ui_ok = loadUI()))
     59    {
     60        /* for starters, load this host */
     61        loadHost(gContext->GetHostName());
    9162
    92     /* for starters, load this host */
    93     loadHost(gContext->GetHostName());
    94 
    95     /* update the information */
    96     refreshKeyInformation();
     63        /* update the information */
     64        refreshKeyInformation();
     65    }
    9766}
    9867
    9968
    10069
    10170/* comments in header */
    102 MythControls::~MythControls() { delete(this->key_bindings); }
     71MythControls::~MythControls() { delete this->key_bindings; }
    10372
    10473
    10574
     
    10978    /* the return value of the method */
    11079    bool retval = true;
    11180
    112     /* by default, there is no popup */
    113     popup = NULL;
    114 
    11581    /* Get the UI widgets that we need to work with */
    116     description = getUITextType("description");
    117     if (!description) {
    118         VERBOSE(VB_ALL, "Unable to load action_description");
     82    if ((description = getUITextType("description")) == NULL)
     83    {
     84        VERBOSE(VB_ALL, "MythControls: Unable to load action_description");
    11985        retval = false;
    12086    }
    12187
    122     control_tree_list=getUIManagedTreeListType("controltree");
    123     if (!control_tree_list)
     88    if ((control_list=getUIListTreeType("controltree")) == NULL)
    12489    {
    125         VERBOSE(VB_ALL, "Unable to load controltree");
     90        VERBOSE(VB_ALL, "MythControls: Unable to load controltree");
    12691        retval = false;
    12792    }
    12893    else {
    12994
    13095        /* set some parameters for the tree */
    131         control_tree_list->showWholeTree(true);
    132         control_tree_list->colorSelectables(true);
    133         focused=control_tree_list;
     96        focused=control_list;
     97        control_list->setActive(true);
    13498    }
    13599
    136100    /* Check that all the buttons are there */
    137101    if ((action_buttons[0] = getUITextButtonType("action_one")) == NULL)
    138102    {
    139         VERBOSE(VB_ALL, "Unable to load first action button");
     103        VERBOSE(VB_ALL, "MythControls: Unable to load first action button");
    140104        retval = false;
    141105    }
    142106    else if ((action_buttons[1] = getUITextButtonType("action_two")) == NULL)
    143107    {
    144         VERBOSE(VB_ALL, "Unable to load second action button");
     108        VERBOSE(VB_ALL, "MythControls: Unable to load second action button");
    145109        retval = false;
    146110    }
    147111    else if ((action_buttons[2] = getUITextButtonType("action_three")) == NULL)
    148112    {
    149         VERBOSE(VB_ALL, "Unable to load thrid action button");
     113        VERBOSE(VB_ALL, "MythControls: Unable to load thrid action button");
    150114        retval = false;
    151115    }
    152116    else if ((action_buttons[3] = getUITextButtonType("action_four")) == NULL)
    153117    {
    154         VERBOSE(VB_ALL, "Unable to load fourth action button");
     118        VERBOSE(VB_ALL, "MythControls: Unable to load fourth action button");
    155119        retval = false;
    156120    }
    157121
     
    177141    {
    178142        focused = action_buttons[0];
    179143        action_buttons[0]->takeFocus();
    180         control_tree_list->looseFocus();
     144        control_list->looseFocus();
     145        control_list->setActive(false);
    181146    }
    182147    else
    183148    {
     
    220185
    221186        if (action == "MENU" || action == "INFO")
    222187        {
    223             /* bring up the menu */
    224             this->actionMenu();
     188            OptionsMenu popup(gContext->GetMainWindow());
     189            if (popup.getOption() == OptionsMenu::SAVE) save();
    225190        }
    226191        else if (action == "SELECT")
    227192        {
    228             if (focused == control_tree_list)
     193            if (focused == control_list)
    229194            {
    230                 if (control_tree_list->getActiveBin() == 1)
    231                     control_tree_list->pushDown();
    232                 else
    233                     focusButton(0);
     195                if (control_list->getDepth() == 0) control_list->MoveRight();
     196                else focusButton(0);
    234197            }
    235198            else {
    236                 popup = new MythPopupBox(gContext->GetMainWindow(),"decision");
    237                 popup->addLabel(tr("Modify Action"),MythPopupBox::Large,false);
    238                 popup->addButton(tr("Set Binding"),this, SLOT(captureKey()));
    239                 popup->addButton(tr("Remove Binding"),this, SLOT(deleteKey()));
    240                 popup->addButton(tr("Cancel"), this,
    241                                  SLOT(killPopup()))->setFocus();
    242                 popup->ShowPopup();
     199                ActionMenu popup(gContext->GetMainWindow());
     200                int result = popup.getOption();
     201                if (result == ActionMenu::SET) addKeyToAction();
     202                else if (result == ActionMenu::REMOVE) deleteKey();
    243203            }
    244204        }
    245205        else if (action == "ESCAPE")
    246206        {
    247             if (focused == control_tree_list)
     207            if (focused == control_list)
    248208            {
    249209                /* ask the user to save if there are unsaved changes*/
    250210                if (key_bindings->hasChanges())
    251211                {
    252                     popup = new MythPopupBox(gContext->GetMainWindow(),
    253                                              "unsaged");
    254                     popup->addLabel(tr("Unsaged Changes"),
    255                                     MythPopupBox::Large,
    256                                     false);
    257 
    258                     popup->addLabel(tr("Would you like to save now?"));
    259                     popup->addButton(tr("Save"), this,
    260                                      SLOT(save()))->setFocus();
    261                     popup->addButton(tr("Exit"), this, SLOT(killPopup()));
    262                     popup->ExecPopup(this, SLOT(killPopup()));
     212                    UnsavedMenu popup(gContext->GetMainWindow());
     213                    if (popup.getOption() == UnsavedMenu::SAVE) save();
    263214                }
    264215
    265216                /* let the user exit */
     
    269220            {
    270221                /* take focus away from the button */
    271222                focused->looseFocus();
    272                 control_tree_list->takeFocus();
    273                 focused = control_tree_list;
     223                focused = control_list;
     224                control_list->takeFocus();
     225                control_list->setActive(true);
    274226            }
    275227        }
    276         else if (action == "UP")
     228        else if ((action == "UP") && (focused == control_list))
    277229        {
    278             if (focused == control_tree_list)
    279             {
    280                 control_tree_list->moveUp();
    281                 refreshKeyInformation();
    282             }
    283             else focusButton(-1);
     230            control_list->MoveUp();
     231            refreshKeyInformation();
    284232        }
    285         else if (action == "DOWN")
     233        else if ((action == "DOWN") && (focused == control_list))
    286234        {
    287             if (focused == control_tree_list)
    288             {
    289                 control_tree_list->moveDown();
    290                 refreshKeyInformation();
    291             }
    292             else focusButton(1);
     235            control_list->MoveDown();
     236            refreshKeyInformation();
    293237        }
    294238        else if (action == "LEFT")
    295239        {
    296             if (focused == control_tree_list)
     240            if (focused==control_list)
    297241            {
    298                 control_tree_list->popUp();
     242                control_list->MoveLeft();
    299243                refreshKeyInformation();
    300244            }
    301245            else focusButton(-1);
    302246        }
    303247        else if (action == "RIGHT")
    304248        {
    305             if (focused == control_tree_list)
     249            if (focused == control_list)
    306250            {
    307                 control_tree_list->pushDown();
    308                 refreshKeyInformation();
     251                if (control_list->getDepth() == 0)
     252                {
     253                    control_list->MoveRight();
     254                    refreshKeyInformation();
     255                }
    309256            }
    310257            else focusButton(1);
    311258        }
    312         else if (action == "PAGEUP")
     259        else if ((action == "PAGEUP") && (focused == control_list))
    313260        {
    314             if (focused == control_tree_list)
    315             {
    316                 control_tree_list->pageUp();
    317                 refreshKeyInformation();
    318             }
     261            control_list->MoveUp(UIListTreeType::MovePage);
     262            refreshKeyInformation();
    319263        }
    320         else if (action == "PAGEDOWN")
     264        else if ((action == "PAGEDOWN") && (focused == control_list))
    321265        {
    322             if (focused == control_tree_list)
    323             {
    324                 control_tree_list->pageDown();
    325                 refreshKeyInformation();
    326             }
     266            control_list->MoveDown(UIListTreeType::MovePage);
     267            refreshKeyInformation();
    327268        }
    328269        else handled = false;
    329270    }
     
    363304/* comments in header */
    364305QString MythControls::getCurrentContext(void) const
    365306{
    366     if (control_tree_list->getActiveBin() == 2)
    367         return control_tree_list->getCurrentNode()->getParent()->getString();
    368     else if (control_tree_list->getActiveBin() == 1)
    369         return control_tree_list->getCurrentNode()->getString();
     307    UIListGenericTree *current = control_list->GetCurrentPosition();
     308    if (control_list->getDepth() == 1 )
     309        return current->getParent()->getString();
     310    else if (control_list->getDepth() == 0)
     311        return current->getString();
    370312    else
    371313        return "";
    372314}
     
    376318/* comments in header */
    377319QString MythControls::getCurrentAction(void) const
    378320{
    379     if (control_tree_list->getActiveBin() == 2)
    380         return control_tree_list->getCurrentNode()->getString();
     321    if (control_list->getDepth() == 1)
     322        return control_list->GetCurrentPosition()->getString();
    381323    else
    382324        return "";
    383325}
     
    389331
    390332    /* create the key bindings and the tree */
    391333    key_bindings = new KeyBindings(hostname);
    392     context_tree = new GenericTree(hostname, 0, false);
    393334    QStringList context_names = key_bindings->getContexts();
    394335
    395     for (size_t i = 0; i < context_names.size(); i++) {
     336    /* Alphabetic order, but jump and global at the top  */
     337    context_names.sort();
     338    context_names.remove(JUMP_CONTEXT);
     339    context_names.remove(GLOBAL_CONTEXT);
     340    context_names.insert(context_names.begin(), 1, GLOBAL_CONTEXT);
     341    context_names.insert(context_names.begin(), 1, JUMP_CONTEXT);
    396342
    397         GenericTree *context_node = new GenericTree(context_names[i], i, true);
     343    UIListGenericTree *root = new UIListGenericTree(NULL, "ROOT");
    398344
    399         /* add the context to the tree of contexts */
    400         context_tree->addNode(context_node);
     345    for (size_t i = 0; i < context_names.size(); i++)
     346    {
     347        UIListGenericTree *context_node;
     348        context_node = new UIListGenericTree(root, context_names[i],
     349                                             context_names[i]);
    401350
    402351        QStringList action_names = key_bindings->getActions(context_names[i]);
     352        action_names.sort();
    403353
    404354        /* add all actions to the context */
    405355        for (size_t j = 0; j < action_names.size(); j++)
    406             context_node->addNode(action_names[j], j, true);
    407 
    408         /* put the data in the tree */
    409         control_tree_list->assignTreeData(context_node);
     356        {
     357            new UIListGenericTree(context_node, action_names[j],
     358                                  action_names[j]);
     359        }
    410360    }
    411 }
    412361
    413 
    414 
    415 void MythControls::killPopup()
    416 {
    417     if (this->popup == NULL) return;
    418 
    419     this->popup->hide();
    420     delete this->popup;
    421     this->popup = NULL;
    422     setActiveWindow();
     362    control_list->SetTree(root);
     363    control_list->setActive(true);
    423364}
    424365
    425366
    426367
    427368/* comments in header */
    428 void MythControls::actionMenu()
    429 {
    430     if (popup != NULL) return;
    431 
    432     popup = new MythPopupBox(gContext->GetMainWindow(), "editaction");
    433     popup->addButton(tr("Save Changes"), this, SLOT(save()));
    434     popup->addButton(tr("Cancel"),this, SLOT(killPopup()))->setFocus();
    435     popup->ShowPopup(this, SLOT(killPopup()));
    436 }
    437 
    438 
    439 
    440 void MythControls::captureKey()
    441 {
    442     killPopup();
    443 
    444     KeyGrabPopupBox * kg = new KeyGrabPopupBox(gContext->GetMainWindow());
    445 
    446     kg->addOKButton(kg->addButton(tr("OK"), this, SLOT(addKeyToAction())));
    447     kg->addButton(tr("Cancel"), this, SLOT(killPopup()));
    448     this->popup = (MythPopupBox*)kg;
    449     this->popup->ShowPopup(this,SLOT(killPopup()));
    450 }
    451 
    452 
    453 
    454369void MythControls::deleteKey()
    455370{
    456 
    457     killPopup();
    458 
    459371    size_t b = focusedButton();
    460372    QString action = getCurrentAction(), context = getCurrentContext();
    461373    QStringList keys = key_bindings->getActionKeys(context, action);
     
    463375    {
    464376        if (!key_bindings->removeActionKey(context, action, keys[b]))
    465377        {
    466             this->popup = new ConflictResolver(gContext->GetMainWindow());
    467             this->popup->ExecPopup(this, SLOT(killPopup()));
     378            InvalidBindingPopup popup(gContext->GetMainWindow());
     379            popup.getOption();
    468380        }
    469381        else refreshKeyInformation();
    470382    }
     
    472384
    473385
    474386
     387/* method description in header */
     388bool MythControls::resolveConflict(ActionID *conflict, int level)
     389{
     390    MythMainWindow *window = gContext->GetMainWindow();
     391
     392    /* prevent a fatal binding */
     393    if (level == KeyBindings::Error)
     394    {
     395        InvalidBindingPopup popup(gContext->GetMainWindow(),
     396                                  conflict->action(),
     397                                  conflict->context());
     398        popup.getOption();
     399        return false;
     400    }
     401    else
     402    {
     403        /* warn the user that this could conflict */
     404        QString message = "This kebinding may conflict with ";
     405        message += conflict->action() + " in the " + conflict->context();
     406        message += " context.  Do you want to bind it anyways?";
     407
     408        if (MythPopupBox::show2ButtonPopup(window, "Conflict Warning",
     409                                           message,"Bind Key","Cancel",0))
     410            return false;
     411    }
     412
     413    return true;
     414}
     415
     416
     417
     418/* method description in header */
    475419void MythControls::addKeyToAction(void)
    476420{
     421    /* grab a key from the user */
     422    KeyGrabPopupBox *kg = new KeyGrabPopupBox(gContext->GetMainWindow());
     423    int result = kg->ExecPopup(kg,SLOT(cancel()));
     424    QString key = kg->getCapturedKey();
     425    delete kg;
     426
     427    /* go no further if canceled */
     428    if (result == 0) return;
     429
     430    /* get the keys for the selected action */
    477431    size_t b = focusedButton();
    478     QString newkey = ((KeyGrabPopupBox*)popup)->getCapturedKeyEvent();
    479432    QString action = getCurrentAction(), context = getCurrentContext();
    480433    QStringList keys = key_bindings->getActionKeys(context, action);
     434
     435    /* dont bother rebinding the same key */
     436    if (keys[b] == key) return;
     437
     438    bool bind = false;
     439    int level;
     440
     441    /* get the potential conflict */
    481442    ActionID *conflict = NULL;
     443    if ((conflict = key_bindings->conflicts(context, key, level)))
     444        bind = resolveConflict(conflict, level);
    482445
    483     /* having got the key, kill the key grabber */
    484     killPopup();
     446    delete conflict;
    485447
     448    /* dont bind if we shouldn't bind */
     449    if (!bind) return;
     450
     451    /* finally bind or rebind a key to the action */
    486452    if (b < keys.count())
    487     {
    488         /* dont replace with the same key */
    489         if (keys[b] != newkey) {
    490             if ((conflict = key_bindings->conflicts(context, newkey)))
    491             {
    492                 this->popup = new ConflictResolver(gContext->GetMainWindow(),
    493                                                    conflict);
    494                 this->popup->ExecPopup(this, SLOT(killPopup()));
    495             }
    496             else key_bindings->replaceActionKey(context,action,newkey,keys[b]);
    497         }
    498     }
    499     else {
    500         if ((conflict = key_bindings->conflicts(context, newkey)))
    501         {
    502             this->popup = new ConflictResolver(gContext->GetMainWindow(),
    503                                                conflict);
    504             this->popup->ExecPopup(this, SLOT(killPopup()));
    505         }
    506         else key_bindings->addActionKey(context, action, newkey);
    507     }
     453        key_bindings->replaceActionKey(context,action, key, keys[b]);
     454    else
     455        key_bindings->addActionKey(context, action, key);
    508456
    509     /* delete the conflict and hide the popup*/
    510     if (conflict) {
    511         delete conflict;
    512         killPopup();
    513     }
    514 
    515457    refreshKeyInformation();
    516458}
    517459
    518 void MythControls::save(void) {
    519     key_bindings->commitChanges();
    520     killPopup();
    521 }
    522 
    523460#endif /* MYTHCONTROLS_CPP */
  • mythcontrols/mythcontrols/keybindings.cpp

     
    4949
    5050
    5151ActionID * KeyBindings::conflicts(const QString & context_name,
    52                                   const QString & key) const
     52                                  const QString & key, int &level) const
    5353{
    5454    const ActionList &ids = actionset.getActions(key);
    5555
     
    6060    /* check the contexts of the other bindings */
    6161    for (size_t i = 0; i < ids.count(); i++)
    6262    {
    63         if (ids[i].context() == JUMP_CONTEXT) return new ActionID(ids[i]);
    64         else if (ids[i].context() == context_name) return new ActionID(ids[i]);
     63        /* jump points, then global, then the same context */
     64        if (ids[i].context() == JUMP_CONTEXT) {
     65            level = KeyBindings::Error;
     66            return new ActionID(ids[i]);
     67        }
     68        else if (ids[i].context() == context_name) {
     69            level = KeyBindings::Error;
     70            return new ActionID(ids[i]);
     71        }
     72        else if (ids[i].context()==GLOBAL_CONTEXT) {
     73            level = KeyBindings::Warning;
     74            return new ActionID(ids[i]);
     75        }
    6576    }
    6677
    6778    /* no conflicts */
     
    7081
    7182
    7283
     84/* method description in header */
     85bool KeyBindings::removeActionKey(const QString & context_name,
     86                     const QString & action_name,
     87                     const QString & key) {
     88
     89    ActionID id(context_name, action_name);
     90
     91    /* dont remove the last manditory binding */
     92    if (getManditoryBindings().contains(id)&&(actionset.getKeys(id).count()<2))
     93        return false;
     94    else
     95        return this->actionset.remove(id,key);
     96}
     97
     98
     99
     100/* method description in header */
    73101void KeyBindings::commitAction(const ActionID & id)
    74102{
    75103
     
    169197    for (query.next(); query.isValid(); query.next())
    170198    {
    171199        ActionID id(JUMP_CONTEXT, query.value(0).toString());
    172         this->actionset.addAction(id,query.value(1).toString(),
    173                                   query.value(2).toString());
     200
     201        if (query.value(1).toString().isEmpty())
     202        {
     203            actionset.addAction(id, query.value(0).toString(),
     204                                query.value(2).toString());
     205        }
     206        else actionset.addAction(id,query.value(1).toString(),
     207                                 query.value(2).toString());
    174208    }
    175209}
    176210
  • mythcontrols/mythcontrols/mythcontrols.h

     
    2323#ifndef MYTHCONTROLS_H
    2424#define MYTHCONTROLS_H
    2525
    26 #include <stdexcept>
    27 
    2826#include <mythtv/mythdialogs.h>
    29 #include <mythtv/mythwidgets.h>
    30 #include <mythtv/uitypes.h>
     27#include <mythtv/uilistbtntype.h>
    3128
    3229#include "keybindings.h"
    3330
     
    4744     * @param parent The main myth window.
    4845     * @param name The name of this window?  I dunno, none of the docs
    4946     * say.
     47     * @param ui_ok Will be set according to weather the UI was
     48     * correctly loaded.
    5049     */
    51     MythControls(MythMainWindow *parent, const char *name=0);
     50    MythControls(MythMainWindow *parent, const char *name=0,
     51                 bool & ui_ok=false);
    5252
    5353    /**
    5454     * @brief Delete the myth controls object.
     
    5656    ~MythControls();
    5757
    5858    /**
    59      * @brief Load up UI.
    60      * @return true if all UI elements were loaded successfully,
    61      * otherwise false it returned.
    62      *
    63      * This method grabs all of the UI "thingies" that are needed by
    64      * mythcontrols.  If this method returns false, the plugin should
    65      * exit since it will probably just core dump.
    66      */
    67     bool loadUI();
    68 
    69     /**
    7059     * @brief Get the currently selected context string.
    7160     * @return The currently selected context string.
    7261     *
     
    8574 protected:
    8675
    8776    /**
     77     * @brief Load up UI.
     78     * @return true if all UI elements were loaded successfully,
     79     * otherwise false it returned.
     80     *
     81     * This method grabs all of the UI "thingies" that are needed by
     82     * mythcontrols.  If this method returns false, the plugin should
     83     * exit since it will probably just core dump.
     84     */
     85    bool loadUI();
     86
     87    /**
    8888     * @brief The key press handler.
    8989     * @param e The key event.
    9090     */
     
    9999    void refreshKeyInformation();
    100100
    101101    /**
    102      * @brief Launches the action menu.
    103      */
    104     void actionMenu();
    105 
    106     /**
    107102     * @brief Load the settings for a particular host.
    108103     * @param hostname The host to load settings for.
    109104     */
     
    125120     */
    126121    size_t focusedButton(void) const;
    127122
     123    /**
     124     * @brief Resolve a potential conflict.
     125     * @return true if the conflict should be bound, otherwise, false
     126     * is returned.
     127     */
     128    bool resolveConflict(ActionID *conflict, int level);
     129
    128130 private slots:
    129131
    130132     /**
    131133      * @brief Add a key to the currently selected action.
    132134      */
    133      void addKeyToAction();
     135     void addKeyToAction(void);
    134136
    135137     /**
    136       * @brief Capture a key press using the key grabber.
    137       */
    138      void captureKey();
    139 
    140      /**
    141138      * @brief Delete the currently active key.
    142139      */
    143140     void deleteKey();
    144141
    145142     /**
    146       * @brief Kill the currently visbile popup window.
    147       */
    148      void killPopup();
    149 
    150      /**
    151143      * @brief Save the settings.
    152144      */
    153      void save();
     145     inline void save(void) { key_bindings->commitChanges(); }
    154146
    155147 private:
    156148
    157149     UIType *focused;
    158      GenericTree * context_tree;
    159      UIManagedTreeListType * control_tree_list;
     150     UIListTreeType *control_list;
    160151     UITextType *description;
    161152     UITextButtonType * action_buttons[Action::MAX_KEYS];
    162153     KeyBindings *key_bindings;
    163      MythPopupBox *popup;
    164154};
    165155
    166156
  • mythcontrols/mythcontrols/keybindings.h

     
    2929#include "actionid.h"
    3030#include "actionset.h"
    3131
    32 
    3332/**
    3433 * @class KeyBindings.
    3534 * @brief Information about the current keybindings.
     
    4342 public:
    4443
    4544  /**
     45   * @brief Levels of conflict
     46   * @li None: Does not conflict
     47   * @li Potential: May conflict.
     48   * @li Fatal: Frontend will become inoperable.
     49   */
     50  enum ConflictLevels { Warning, Error};
     51
     52  /**
    4653   * @brief Create a new KeyBindings instance.
    4754   * @param hostname The host for which to create the key bindings.
    4855   */
     
    111118   * @brief Determine if adding a key would cause a conflict.
    112119   * @param context_name The name of the context.
    113120   * @param key The key to add.
     121   * @param level The level of conflict.  Check this if the return
     122   * value is not NULL
    114123   * @return true if adding the key would cause a conflict.
    115124   *
    116125   * Conflicts occur if:
    117126   * @li the key is a jump point, but is bound elsewhere
    118127   * @li the key is already bound to a jumppoint.
     128   * @li the key is bound to something in the global context.
    119129   * @li the key is bound to something else in the specified context
     130   *
     131   * If the method does not return NULL, check the value given to
     132   * level.  Warnings can be ignored (at the users disgression), but
     133   * errors should be prevented no matter what.  If they dont like it,
     134   * they can learn SQL.
    120135   */
    121136  ActionID * conflicts(const QString & context_name,
    122                        const QString & key) const;
     137                       const QString & key, int &level) const;
    123138
    124139  /**
    125140   * @brief Replace a key in an action.
     
    152167   */
    153168  bool removeActionKey(const QString & context_name,
    154169                       const QString & action_name,
    155                        const QString & key) {
    156       return this->actionset.remove(ActionID(context_name, action_name),key);
    157   }
     170                       const QString & key);
    158171
    159172  /**
    160173   * @brief Set the manditory bindings to their defaults.
  • mythcontrols/mythcontrols/keygrabber.cpp

     
    2727
    2828#include "keygrabber.h"
    2929
     30#include <mythtv/mythcontext.h>
    3031
    3132
    3233KeyGrabPopupBox::KeyGrabPopupBox(MythMainWindow *window)
     
    3637    this->has_captured = false;
    3738    addLabel("Press A Key", Large, false);
    3839    key_label = addLabel("Waiting for key press", Small, false);
     40
     41    ok_button = this->addButton(tr("OK"), this, SLOT(acceptBinding()));
     42    this->addButton(tr("Cancel"), this, SLOT(cancel()));
     43
    3944    this->grabKeyboard();
    4045}
    4146
     
    8287    /* accept events while we are capturing */
    8388    if (this->is_capturing) e->accept();
    8489    else MythPopupBox::keyPressEvent(e);
     90}
    8591
    86     cout << QString(QKeySequence(Qt::UNICODE_ACCEL & e->key())) << endl;
     92InvalidBindingPopup::InvalidBindingPopup(MythMainWindow *window)
     93    : MythPopupBox(window, "invalidbinding")
     94{
     95    QString warning = "This action is manditory and needs at least one key"
     96        " bound to it.  Instead, try rebinding with another key.";
     97    addLabel("Manditory Action", Large, false);
     98    addLabel(warning, Small, true);
    8799}
     100
     101
     102
     103InvalidBindingPopup::InvalidBindingPopup(MythMainWindow *window,
     104                                         const QString &action,
     105                                         const QString &context)
     106    : MythPopupBox(window, "invalidbinding")
     107{
     108    QString message = "This kebinding conflicts with ";
     109    message += action + " in the " + context;
     110    message += " context.";
     111
     112    addLabel("Conflicting Binding", Large, false);
     113    addLabel(message, Small, true);
     114}
     115
     116
     117
     118OptionsMenu::OptionsMenu(MythMainWindow *window)
     119    : MythPopupBox(window, "optionmenu")
     120{
     121    addLabel(tr("Options"), Large, false);
     122    addButton(tr("Save"), this, SLOT(save()));
     123    addButton(tr("Cancel"), this, SLOT(cancel()))->setFocus();
     124}
     125   
     126
     127ActionMenu::ActionMenu(MythMainWindow *window)
     128    : MythPopupBox(window, "actionmenu")
     129{
     130    addLabel(tr("Modify Action"), Large, false);
     131    addButton(tr("Set Binding"), this, SLOT(set()));
     132    addButton(tr("Remove Binding"), this, SLOT(remove()));
     133    addButton(tr("Cancel"), this, SLOT(cancel()))->setFocus();
     134}
     135
     136UnsavedMenu::UnsavedMenu(MythMainWindow *window)
     137    : MythPopupBox(window, "unsavedmenu")
     138{
     139    addLabel(tr("Unsaged Changes"), Large, false);
     140    addLabel(tr("Would you like to save now?"));
     141    addButton(tr("Save"), this, SLOT(save()))->setFocus();
     142    addButton(tr("Exit"), this, SLOT(cancel()));
     143}
  • mythcontrols/mythcontrols/keygrabber.h

     
    4444    KeyGrabPopupBox(MythMainWindow * window);
    4545
    4646    /**
    47      * @brief Add the OK button.
    48      * @param button The button that will be hilighed once a key has
    49      * been captured.
     47     * @brief Get the string containing the captured key event.
    5048     */
    51     inline void addOKButton(QButton *button) { ok_button = button; }
     49    inline QString getCapturedKey() { return this->captured_key_event; }
    5250
     51 public slots:
     52
    5353    /**
    54      * @brief Get the string containing the captured key event.
     54     * @brief Accept the captured keybinding.
     55     *
     56     * The QString provided in the constructor will be set to the
     57     * captured key value.
    5558     */
    56     inline QString getCapturedKeyEvent() { return this->captured_key_event; }
     59    inline void acceptBinding(void) { done(1); }
    5760
     61    /**
     62     * @brief Reject the captured key binding.
     63     *
     64     * The QString provided in the constructor will be set to NULL.
     65     */
     66    inline void cancel(void) { done(0); }
     67
    5868 protected:
    5969
    6070    /**
     
    7787    QButton *ok_button;
    7888    QLabel *key_label;
    7989};
     90
     91
     92/**
     93 * @class InvalidBindingPopup
     94 * @brief Tells the user that they are being bad!!!
     95 */
     96class InvalidBindingPopup : public MythPopupBox
     97{
     98    Q_OBJECT;
     99
     100 public:
     101
     102    /**
     103     * @brief Create a popup that explains that they are removing a
     104     * critical key binding.
     105     * @param window The main myth window.
     106     */
     107    InvalidBindingPopup(MythMainWindow *window);
     108
     109    /**
     110     * @brief Tell the user that the binding conflicts with another
     111     * action.
     112     */
     113    InvalidBindingPopup(MythMainWindow *window, const QString &action,
     114                        const QString &context);
     115
     116    /**
     117     * @brief Execute the error popup
     118     */
     119    inline int getOption(void) { return ExecPopup(this,SLOT(finish())); }
     120
     121 protected slots:
     122    /**
     123     * @brief Close the popup.
     124     */
     125    inline void finish(void) { done(0); }
     126};
     127
     128
     129/**
     130 * @class OptionsMenu
     131 * @brief A popup containing a list of options.
     132 */
     133class OptionsMenu : public MythPopupBox
     134{
     135
     136    Q_OBJECT;
     137
     138 public:
     139
     140    enum actons { SAVE, CANCEL };
     141
     142    /**
     143     * @brief Create a new action window.
     144     */
     145    OptionsMenu(MythMainWindow *window);
     146
     147    /**
     148     * @brief Execute the option popup.
     149     */
     150    inline int getOption(void) { return ExecPopup(this,SLOT(cancel())); }
     151
     152 public slots:
     153
     154    /**
     155     * @brief Slot to connect to when the save button is pressed.
     156     */
     157    inline void save(void) { done(OptionsMenu::SAVE); }
     158
     159    /**
     160     * @brief Slot to connect to when the cancel button is pressed.
     161     */
     162    inline void cancel(void) { done(OptionsMenu::CANCEL); }
     163
     164};
     165
     166
     167
     168/**
     169 * @class ActionMenu
     170 * @brief A popup listing ways to modify an action.
     171 */
     172class ActionMenu : public MythPopupBox
     173{
     174
     175        Q_OBJECT;
     176
     177 public:
     178
     179    enum actons { SET, REMOVE, CANCEL };
     180
     181    /**
     182     * @brief Create a new action window.
     183     */
     184    ActionMenu(MythMainWindow *window);
     185
     186    /**
     187     * @brief Execute the option popup.
     188     */
     189    inline int getOption(void) { return ExecPopup(this,SLOT(cancel())); }
     190
     191 public slots:
     192
     193    /**
     194     * @brief Slot to connect to when the set button is pressed.
     195     */
     196    inline void set(void) { done(ActionMenu::SET); }
     197
     198    /**
     199     * @brief Slot to connect to when the remove button is pressed.
     200     */
     201    inline void remove(void) { done(ActionMenu::REMOVE); }
     202
     203    /**
     204     * @brief Slot to connect to when the cancel button is pressed.
     205     */
     206    inline void cancel(void) { done(ActionMenu::CANCEL); }
     207
     208};
     209
     210/**
     211 * @class OptionsMenu
     212 * @brief A popup containing a list of options.
     213 */
     214class UnsavedMenu : public MythPopupBox
     215{
     216
     217    Q_OBJECT;
     218
     219 public:
     220
     221    enum actons { SAVE, EXIT };
     222
     223    /**
     224     * @brief Create a new action window.
     225     */
     226    UnsavedMenu(MythMainWindow *window);
     227
     228    /**
     229     * @brief Execute the option popup.
     230     */
     231    inline int getOption(void) { return ExecPopup(this,SLOT(cancel())); }
     232
     233 public slots:
     234
     235    /**
     236     * @brief Slot to connect to when the save button is pressed.
     237     */
     238    inline void save(void) { done(UnsavedMenu::SAVE); }
     239
     240    /**
     241     * @brief Slot to connect to when the cancel button is pressed.
     242     */
     243    inline void cancel(void) { done(UnsavedMenu::EXIT); }
     244
     245};
  • mythcontrols/mythcontrols/mythcontrols.pro

     
    11include ( ../../settings.pro )
    22
    33TEMPLATE = lib
    4 CONFIG += plugin thread warn_on debug
     4CONFIG += plugin thread
    55TARGET = mythcontrols
    66target.path = $${PREFIX}/lib/mythtv/plugins
    77INSTALLS += target
  • mythcontrols/mythcontrols/main.cpp

     
    2626using namespace std;
    2727
    2828#include "mythcontrols.h"
     29#include <mythtv/mythdialogs.h>
    2930
    3031
    31 
    3232/**
    33  * @name Plugin API
    34  *
    35  * The following methods are required by all MythTV plugins.
     33 * @brief Initializes the plugin.
     34 * @param libversion The mythtv library version.
     35 * @return zero if all is well, otherwise, less than zero
    3636 */
    37 //@{
    38 extern "C" {
    39 
    40   /**
    41    * @brief Called by mythtv to initialize the plugin.
    42    * @param libversion Used to make sure that the requried version of
    43    * the library is being used.
    44    * @return I dont really know what difference your return values makes.
    45    * @todo Find out the difference this return values makes.
    46    */
    47   int mythplugin_init(const char *libversion);
    48 
    49   /**
    50    * @brief Runs the plugin.
    51    * @return I dont really know what difference your return values makes.
    52    * @todo Find out the difference this return values makes.
    53    */
    54   int mythplugin_run(void);
    55 
    56   /**
    57    * @brief Called to configure the plugin.
    58    * @return I dont really know what difference your return values makes.
    59    * @todo Find out the difference this return values makes.
    60    */
    61   int mythplugin_config(void);
    62 }
    63 //@}
    64 
    65 
    66 /* documented above */
    67 int mythplugin_init(const char *libversion)
     37extern "C" int mythplugin_init(const char *libversion)
    6838{
    6939    if (!gContext->TestPopupVersion("mythcontrols", libversion,
    7040                                    MYTH_BINARY_VERSION)) return -1;
     
    7343
    7444
    7545
    76 /* documented above */
    77 int mythplugin_run (void)
     46/**
     47 * @brief Runs the plugin.
     48 * @return zero if all is well, otherwise, less than zero
     49 */
     50extern "C" int mythplugin_run (void)
    7851{
    79     MythControls controls(gContext->GetMainWindow(), "controls");
     52    bool uiloaded;
     53    MythMainWindow *window = gContext->GetMainWindow();
    8054
     55    /* create the keybinding plugin.  uiloaded will be set to false
     56     * if the theme was not correct */
     57    MythControls controls(window, "controls", uiloaded);
     58
    8159    /* if the UI is successfully loaded, just giv'er*/
    82     if (controls.loadUI())
     60    if (uiloaded)
    8361    {
    8462        controls.exec();
    8563        return 0;   
    8664    }
    8765    else
    8866    {
    89         VERBOSE(VB_ALL, "Unable to load theme, exiting");
     67        MythPopupBox::showOkPopup(window, "Theme Error", "Could not load the "
     68                                  "keybinding plugin's theme.  Check the "
     69                                  "console for detailed output.");
     70
    9071        return -1;
    9172    }
    9273}
    9374
    9475
    9576
    96 /* documented above*/
    97 int mythplugin_config (void) { return 0; }
     77/**
     78 * @brief Configures the plugin.
     79 * @return zero.
     80 */
     81extern "C" int mythplugin_config (void) { return 0; }
    9882
    9983
    10084
  • mythcontrols/mythcontrols/actionset.cpp

     
    2222#ifndef ACTIONSET_CPP
    2323#define ACTIONSET_CPP
    2424
    25 #include <iostream>
    26 
    2725#include <qmap.h>
    2826#include <qdict.h>
    2927#include <qvaluelist.h>
     
    3634#include "actionset.h"
    3735
    3836
    39 
    4037/* method description in header */
    4138bool ActionSet::add(const ActionID &id, const QString &key)
    4239{
     
    5451            ids.push_back(id);
    5552            this->modify(id);   
    5653            return true;
    57         } else cerr << "Key not added" << endl;
    58     } else cerr << "No action" << endl;
     54        }
     55    }
    5956
    6057    return false;
    6158}
  • mythcontrols/mythcontrols/controls-ui.xml

     
    33
    44 <window name="controls">
    55
    6    <font name="selected" face="Arial">
    7      <color>#ffffff</color>
    8      <size>14</size>
    9      <bold>yes</bold>
    10    </font>
     6  <font name="active" face="Arial">
     7   <color>#ffffff</color>
     8   <size>14</size>
     9   <bold>yes</bold>
     10  </font>
    1111
    12    <font name="active" face="Arial">
    13      <color>#aaaaaa</color>
    14      <size>14</size>
    15      <bold>yes</bold>
    16    </font>
     12  <font name="inactive" face="Arial">
     13   <color>#9999cc</color>
     14   <size>14</size>
     15   <bold>yes</bold>
     16  </font>
    1717
    18    <font name="inactive" face="Arial">
    19      <color>#9999cc</color>
    20      <size>14</size>
    21      <bold>yes</bold>
    22    </font>
     18  <font name="keys" face="Arial">
     19   <color>#000000</color>
     20   <size>18</size>
     21   <shadow>1,1</shadow>
     22   <bold>yes</bold>
     23  </font>
    2324
    24    <font name="selectable" face="Arial">
    25      <color>#8cdeff</color>
    26      <size>14</size>
    27      <bold>yes</bold>
    28    </font>
     25  <font name="info" face="Arial">
     26   <color>#ffffff</color>
     27   <size>18</size>
     28   <shadow>1,1</shadow>
     29   <bold>yes</bold>
     30  </font>
    2931
    30    <font name="labels" face="Arial">
    31      <color>#ffffff</color>
    32      <size>16</size>
    33      <shadow>1,1</shadow>
    34      <bold>yes</bold>
    35    </font>
     32  <font name="infotitle" face="Arial">
     33   <color>#ffffff</color>
     34   <size>24</size>
     35   <shadow>10,10</shadow>
     36   <bold>yes</bold>
     37  </font>
    3638
    37    <font name="keys" face="Arial">
    38      <color>#000000</color>
    39      <size>18</size>
    40      <shadow>1,1</shadow>
    41      <bold>yes</bold>
    42    </font>
     39  <container name="controls">
     40   <area>20,20,780,380</area>
     41   <listtreearea name="controltree" draworder="0">
     42    <area>0,0,760,360</area>
     43    <listsize>0,0,370,360</listsize>
     44    <leveloffset>15</leveloffset>
     45    <gradient type="unselected" start="#505050" end="#000000" alpha="100"/>
     46    <gradient type="selected" start="#52CA38" end="#349838" alpha="255"/>
     47    <fcnfont name="active" function="active"/>
     48    <fcnfont name="inactive" function="inactive"/>
     49   </listtreearea>
     50  </container>
    4351
    44    <font name="info" face="Arial">
    45      <color>#ffffff</color>
    46      <size>18</size>
    47      <shadow>1,1</shadow>
    48      <bold>yes</bold>
    49    </font>
     52  <container name="keys">
     53   <area>20,400,780,180</area>
    5054
    51    <font name="infotitle" face="Arial">
    52      <color>#ffffff</color>
    53      <size>24</size>
    54      <shadow>10,10</shadow>
    55      <bold>yes</bold>
    56    </font>
     55   <textbutton name="action_one" draworder="0">
     56    <position>20,20</position>
     57    <image function="on" filename="kb-button-on.png"/>
     58    <image function="off" filename="kb-button-off.png"/>
     59    <font>keys</font>
     60   </textbutton>
    5761
    58    <font name="message" face="Arial">
    59      <color>#ffffff</color>
    60      <size>16</size>
    61      <shadow>1,1</shadow>
    62      <bold>yes</bold>
    63    </font>
     62   <textbutton name="action_two" draworder="0">
     63    <position>200,20</position>
     64    <image function="on" filename="kb-button-on.png"/>
     65    <image function="off" filename="kb-button-off.png"/>
     66    <font>keys</font>
     67   </textbutton>
    6468
    65    <container name="controls">
    66      <area>0,0,800,350</area>
     69   <textbutton name="action_three" draworder="0">
     70    <position>390,20</position>
     71    <image function="on" filename="kb-button-on.png"/>
     72    <image function="off" filename="kb-button-off.png"/>
     73    <font>keys</font>
     74   </textbutton>
    6775
    68      <managedtreelist name="controltree" draworder="1" bins="2">
    69        <area>0,40,800,310</area>
     76   <textbutton name="action_four" draworder="0">
     77    <position>580,20</position>
     78    <image function="on" filename="kb-button-on.png"/>
     79    <image function="off" filename="kb-button-off.png"/>
     80    <font>keys</font>
     81   </textbutton>
    7082
    71        <image function="selectionbar" filename="bar.png"/>
    72        <image function="uparrow" filename="scrollarrow-up.png"/>
    73        <image function="downarrow" filename="scrollarrow-dn.png"/>
    74        <image function="leftarrow" filename="scrollarrow-left.png"/>
    75        <image function="rightarrow" filename="scrollarrow-right.png"/>
     83   <textarea name="description" draworder="1" allign="left">
     84    <font>info</font>
     85    <area>30,100,740,140</area>
     86    <multiline>yes</multiline>
     87   </textarea>
    7688
    77        <bin number="1">
    78          <area>30,14,190,250</area>
    79          <fcnfont name="active" function="active"/>
    80          <fcnfont name="inactive" function="inactive"/>
    81          <fcnfont name="selected" function="selected"/>
    82          <fcnfont name="selectable" function="selectable"/>     
    83        </bin>
     89  </container>
    8490
    85        <bin number="2">
    86          <area>240,14,530,265</area>
    87          <fcnfont name="active" function="active"/>
    88          <fcnfont name="inactive" function="inactive"/>
    89          <fcnfont name="active" function="selected"/>
    90          <fcnfont name="selectable" function="selectable"/>     
    91        </bin>
    92 
    93      </managedtreelist>
    94 
    95      <image name="showinglines" draworder="2" fleximage="yes">
    96        <filename>showings.png</filename>
    97        <position>0,0</position>
    98      </image>
    99 
    100    </container>
    101 
    102    <container name="keys">
    103      <area>0,300,800,320</area>
    104 
    105      <textarea name="infotitle" draworder="0">
    106        <font>infotitle</font>
    107        <area>282,20,236,40</area>
    108        <value>Key Bindings</value>
    109      </textarea>
    110 
    111      <textbutton name="action_one" draworder="0">
    112        <position>20,100</position>
    113        <image function="on" filename="kb-button-on.png"/>
    114        <image function="off" filename="kb-button-off.png"/>
    115        <font>keys</font>
    116      </textbutton>
    117 
    118      <textbutton name="action_two" draworder="0">
    119        <position>200,100</position>
    120        <image function="on" filename="kb-button-on.png"/>
    121        <image function="off" filename="kb-button-off.png"/>
    122        <font>keys</font>
    123      </textbutton>
    124 
    125      <textbutton name="action_three" draworder="0">
    126        <position>390,100</position>
    127        <image function="on" filename="kb-button-on.png"/>
    128        <image function="off" filename="kb-button-off.png"/>
    129        <font>keys</font>
    130      </textbutton>
    131 
    132      <textbutton name="action_four" draworder="0">
    133        <position>580,100</position>
    134        <image function="on" filename="kb-button-on.png"/>
    135        <image function="off" filename="kb-button-off.png"/>
    136        <font>keys</font>
    137      </textbutton>
    138 
    139      <image name="actionlines" draworder="1" allign="left">
    140        <filename>cr-lines.png</filename>
    141        <position>0,0</position>
    142      </image>
    143 
    144      <textarea name="description" draworder="1" allign="left">
    145        <font>info</font>
    146        <area>30,180,740,140</area>
    147        <multiline>yes</multiline>
    148      </textarea>
    149 
    150      
    151    </container>
    152 
    15391 </window>
    15492</mythuitheme>