|
MythTV
0.26-pre
|
00001 // -*- Mode: c++ -*- 00029 #include "mythcontrols.h" 00030 00031 // Qt headers 00032 #include <QStringList> 00033 #include <QCoreApplication> 00034 00035 // MythTV headers 00036 #include "mythcorecontext.h" 00037 #include "mythmainwindow.h" 00038 00039 // MythUI headers 00040 #include "mythuitext.h" 00041 #include "mythuibutton.h" 00042 #include "mythuibuttonlist.h" 00043 #include "mythdialogbox.h" 00044 00045 // MythControls headers 00046 #include "keygrabber.h" 00047 00048 #define LOC QString("MythControls: ") 00049 #define LOC_ERR QString("MythControls, Error: ") 00050 00056 MythControls::MythControls(MythScreenStack *parent, const char *name) 00057 : MythScreenType (parent, name) 00058 { 00059 m_currentView = kActionsByContext; 00060 m_leftList = m_rightList = NULL; 00061 m_description = m_leftDescription = m_rightDescription = NULL; 00062 m_bindings = NULL; 00063 00064 m_leftListType = kContextList; 00065 m_rightListType = kActionList; 00066 00067 m_menuPopup = NULL; 00068 } 00069 00070 MythControls::~MythControls() 00071 { 00072 Teardown(); 00073 } 00074 00075 void MythControls::Teardown(void) 00076 { 00077 if (m_bindings) 00078 { 00079 delete m_bindings; 00080 m_bindings = NULL; 00081 } 00082 00083 m_contexts.clear(); 00084 } 00085 00091 bool MythControls::Create(void) 00092 { 00093 bool foundtheme = false; 00094 00095 // Load the theme for this screen 00096 foundtheme = LoadWindowFromXML("controls-ui.xml", "controls", this); 00097 00098 if (!foundtheme) 00099 return false; 00100 00101 m_description = dynamic_cast<MythUIText *>(GetChild("description")); 00102 m_leftList = dynamic_cast<MythUIButtonList *>(GetChild("leftlist")); 00103 m_rightList = dynamic_cast<MythUIButtonList *>(GetChild("rightlist")); 00104 m_leftDescription = dynamic_cast<MythUIText *>(GetChild("leftdesc")); 00105 m_rightDescription = dynamic_cast<MythUIText *>(GetChild("rightdesc")); 00106 00107 if (!m_description || !m_leftList || !m_rightList || 00108 !m_leftDescription || !m_rightDescription) 00109 { 00110 LOG(VB_GENERAL, LOG_ERR, "Theme is missing critical theme elements."); 00111 return false; 00112 } 00113 00114 connect(m_leftList, SIGNAL(itemSelected(MythUIButtonListItem*)), 00115 SLOT(LeftSelected(MythUIButtonListItem*))); 00116 connect(m_leftList, SIGNAL(itemClicked(MythUIButtonListItem*)), 00117 SLOT(LeftPressed(MythUIButtonListItem*))); 00118 00119 connect(m_rightList, SIGNAL(itemSelected(MythUIButtonListItem*)), 00120 SLOT(RightSelected(MythUIButtonListItem*))); 00121 connect(m_rightList, SIGNAL(itemClicked(MythUIButtonListItem*)), 00122 SLOT(RightPressed(MythUIButtonListItem*))); 00123 connect(m_rightList, SIGNAL(TakingFocus()), 00124 SLOT(RefreshKeyInformation())); 00125 00126 for (uint i = 0; i < Action::kMaximumNumberOfBindings; i++) 00127 { 00128 MythUIButton *button = dynamic_cast<MythUIButton *> 00129 (GetChild(QString("action_%1").arg(i))); 00130 00131 if (!button) 00132 { 00133 LOG(VB_GENERAL, LOG_ERR, LOC + 00134 QString("Unable to load action button action_%1").arg(i)); 00135 00136 return false; 00137 } 00138 00139 connect(button, SIGNAL(Clicked()), SLOT(ActionButtonPressed())); 00140 00141 m_actionButtons.append(button); 00142 } 00143 00144 BuildFocusList(); 00145 00146 LoadData(gCoreContext->GetHostName()); 00147 00148 /* start off with the actions by contexts view */ 00149 m_currentView = kActionsByContext; 00150 SetListContents(m_leftList, m_bindings->GetContexts(), true); 00151 UpdateRightList(); 00152 00153 return true; 00154 } 00155 00161 void MythControls::ChangeButtonFocus(int direction) 00162 { 00163 if ((m_leftListType != kContextList) || (m_rightListType != kActionList)) 00164 return; 00165 00166 if (direction == 0) 00167 SetFocusWidget(m_actionButtons.at(0)); 00168 } 00169 00173 void MythControls::LeftPressed(MythUIButtonListItem *item) 00174 { 00175 (void) item; 00176 NextPrevWidgetFocus(true); 00177 } 00178 00182 void MythControls::RightPressed(MythUIButtonListItem *item) 00183 { 00184 (void) item; 00185 if (m_currentView == kActionsByContext) 00186 ChangeButtonFocus(0); 00187 } 00188 00192 void MythControls::ActionButtonPressed() 00193 { 00194 QString key = GetCurrentKey(); 00195 if (!key.isEmpty()) 00196 { 00197 QString label = tr("Modify Action"); 00198 00199 MythScreenStack *popupStack = 00200 GetMythMainWindow()->GetStack("popup stack"); 00201 00202 m_menuPopup = 00203 new MythDialogBox(label, popupStack, "actionmenu"); 00204 00205 if (m_menuPopup->Create()) 00206 popupStack->AddScreen(m_menuPopup); 00207 00208 m_menuPopup->SetReturnEvent(this, "action"); 00209 00210 m_menuPopup->AddButton(tr("Set Binding")); 00211 m_menuPopup->AddButton(tr("Remove Binding")); 00212 } 00213 else // for blank keys, no reason to ask what to do 00214 GrabKey(); 00215 } 00216 00220 void MythControls::ChangeView(void) 00221 { 00222 QString label = tr("Change View"); 00223 00224 MythScreenStack *popupStack = 00225 GetMythMainWindow()->GetStack("popup stack"); 00226 00227 m_menuPopup = 00228 new MythDialogBox(label, popupStack, "mcviewmenu"); 00229 00230 if (m_menuPopup->Create()) 00231 popupStack->AddScreen(m_menuPopup); 00232 00233 m_menuPopup->SetReturnEvent(this, "view"); 00234 00235 m_menuPopup->AddButton(tr("Actions By Context")); 00236 m_menuPopup->AddButton(tr("Contexts By Key")); 00237 m_menuPopup->AddButton(tr("Keys By Context")); 00238 00239 } 00240 00241 void MythControls::ShowMenu() 00242 { 00243 QString label = tr("Options"); 00244 00245 MythScreenStack *popupStack = 00246 GetMythMainWindow()->GetStack("popup stack"); 00247 00248 m_menuPopup = 00249 new MythDialogBox(label, popupStack, "optionmenu"); 00250 00251 if (m_menuPopup->Create()) 00252 popupStack->AddScreen(m_menuPopup); 00253 00254 m_menuPopup->SetReturnEvent(this, "option"); 00255 00256 m_menuPopup->AddButton(tr("Save")); 00257 m_menuPopup->AddButton(tr("Change View")); 00258 m_menuPopup->AddButton(tr("Reset All Keys to Defaults")); 00259 } 00260 00261 void MythControls::Close() 00262 { 00263 if (m_bindings && m_bindings->HasChanges()) 00264 { 00265 /* prompt user to save changes */ 00266 QString label = tr("Save changes?"); 00267 00268 MythScreenStack *popupStack = 00269 GetMythMainWindow()->GetStack("popup stack"); 00270 00271 MythConfirmationDialog *confirmPopup 00272 = new MythConfirmationDialog(popupStack, label, true); 00273 00274 if (confirmPopup->Create()) 00275 popupStack->AddScreen(confirmPopup); 00276 00277 confirmPopup->SetReturnEvent(this, "exit"); 00278 } 00279 else 00280 MythScreenType::Close(); 00281 } 00282 00287 void MythControls::LeftSelected(MythUIButtonListItem*) 00288 { 00289 UpdateRightList(); 00290 } 00291 00296 void MythControls::RightSelected(MythUIButtonListItem*) 00297 { 00298 RefreshKeyInformation(); 00299 } 00300 00301 00308 void MythControls::SetListContents( 00309 MythUIButtonList *uilist, const QStringList &contents, bool arrows) 00310 { 00311 // remove all strings from the current list 00312 uilist->Reset(); 00313 00314 // add each new string 00315 QStringList::const_iterator it = contents.begin(); 00316 for (; it != contents.end(); ++it) 00317 { 00318 QString tmp = *it; tmp.detach(); 00319 MythUIButtonListItem *item = new MythUIButtonListItem(uilist, tmp); 00320 item->setDrawArrow(arrows); 00321 } 00322 } 00323 00327 void MythControls::UpdateRightList(void) 00328 { 00329 // get the selected item in the right list. 00330 MythUIButtonListItem *item = m_leftList->GetItemCurrent(); 00331 00332 if (!item) 00333 return; 00334 00335 QString rtstr = item->GetText(); 00336 00337 switch(m_currentView) 00338 { 00339 case kActionsByContext: 00340 SetListContents(m_rightList, m_contexts[rtstr]); 00341 break; 00342 case kKeysByContext: 00343 SetListContents(m_rightList, m_bindings->GetContextKeys(rtstr)); 00344 break; 00345 case kContextsByKey: 00346 SetListContents(m_rightList, m_bindings->GetKeyContexts(rtstr)); 00347 break; 00348 } 00349 } 00350 00355 void MythControls::RefreshKeyInformation(void) 00356 { 00357 for (uint i = 0; i < Action::kMaximumNumberOfBindings; i++) 00358 m_actionButtons.at(i)->SetText(""); 00359 00360 if (GetFocusWidget() == m_leftList) 00361 { 00362 m_description->Reset(); 00363 return; 00364 } 00365 00366 const QString context = GetCurrentContext(); 00367 const QString action = GetCurrentAction(); 00368 00369 QString desc = m_bindings->GetActionDescription(context, action); 00370 m_description->SetText(tr(desc.toAscii().constData())); 00371 00372 QStringList keys = m_bindings->GetActionKeys(context, action); 00373 for (int i = 0; (i < keys.count()) && 00374 (i < (int)Action::kMaximumNumberOfBindings); i++) 00375 { 00376 m_actionButtons.at(i)->SetText(keys[i]); 00377 } 00378 } 00379 00380 00388 QString MythControls::GetCurrentContext(void) 00389 { 00390 if (m_leftListType == kContextList) 00391 return m_leftList->GetItemCurrent()->GetText(); 00392 00393 if (GetFocusWidget() == m_leftList) 00394 return QString(); 00395 00396 QString desc = m_rightList->GetItemCurrent()->GetText(); 00397 int loc = desc.indexOf(" => "); 00398 if (loc == -1) 00399 return QString(); // Should not happen 00400 00401 if (m_rightListType == kContextList) 00402 return desc.left(loc); 00403 00404 return desc.mid(loc + 4); 00405 } 00406 00414 QString MythControls::GetCurrentAction(void) 00415 { 00416 if (m_leftListType == kActionList) 00417 { 00418 if (m_leftList && m_leftList->GetItemCurrent()) 00419 { 00420 QString tmp = m_leftList->GetItemCurrent()->GetText(); 00421 tmp.detach(); 00422 return tmp; 00423 } 00424 return QString(); 00425 } 00426 00427 if (GetFocusWidget() == m_leftList) 00428 return QString(); 00429 00430 if (!m_rightList || !m_rightList->GetItemCurrent()) 00431 return QString(); 00432 00433 QString desc = m_rightList->GetItemCurrent()->GetText(); 00434 if (kContextList == m_leftListType && 00435 kActionList == m_rightListType) 00436 { 00437 desc.detach(); 00438 return desc; 00439 } 00440 00441 int loc = desc.indexOf(" => "); 00442 if (loc == -1) 00443 return QString(); // should not happen.. 00444 00445 if (m_rightListType == kActionList) 00446 return desc.left(loc); 00447 00448 QString rv = desc.mid(loc+4); 00449 if (rv == "<none>") 00450 return QString(); 00451 00452 return rv; 00453 } 00454 00459 uint MythControls::GetCurrentButton(void) 00460 { 00461 for (uint i = 0; i < Action::kMaximumNumberOfBindings; i++) 00462 { 00463 MythUIButton *button = m_actionButtons.at(i); 00464 MythUIType *uitype = GetFocusWidget(); 00465 if (uitype == button) 00466 return i; 00467 } 00468 00469 return Action::kMaximumNumberOfBindings; 00470 } 00471 00479 QString MythControls::GetCurrentKey(void) 00480 { 00481 MythUIButtonListItem* currentButton; 00482 if (m_leftListType == kKeyList && 00483 (currentButton = m_leftList->GetItemCurrent())) 00484 { 00485 return currentButton->GetText(); 00486 } 00487 00488 if (GetFocusWidget() == m_leftList) 00489 return QString(); 00490 00491 if ((m_leftListType == kContextList) && (m_rightListType == kActionList)) 00492 { 00493 QString context = GetCurrentContext(); 00494 QString action = GetCurrentAction(); 00495 uint b = GetCurrentButton(); 00496 QStringList keys = m_bindings->GetActionKeys(context, action); 00497 00498 if (b < (uint)keys.count()) 00499 return keys[b]; 00500 00501 return QString(); 00502 } 00503 00504 currentButton = m_rightList->GetItemCurrent(); 00505 QString desc; 00506 if (currentButton) 00507 desc = currentButton->GetText(); 00508 00509 int loc = desc.indexOf(" => "); 00510 if (loc == -1) 00511 return QString(); // Should not happen 00512 00513 00514 if (m_rightListType == kKeyList) 00515 return desc.left(loc); 00516 00517 return desc.mid(loc + 4); 00518 } 00519 00524 void MythControls::LoadData(const QString &hostname) 00525 { 00526 /* create the key bindings and the tree */ 00527 m_bindings = new KeyBindings(hostname); 00528 m_sortedContexts = m_bindings->GetContexts(); 00529 00530 /* Alphabetic order, but jump and global at the top */ 00531 m_sortedContexts.sort(); 00532 m_sortedContexts.removeAll(ActionSet::kJumpContext); 00533 m_sortedContexts.removeAll(ActionSet::kGlobalContext); 00534 m_sortedContexts.insert(m_sortedContexts.begin(), 00535 ActionSet::kGlobalContext); 00536 m_sortedContexts.insert(m_sortedContexts.begin(), 00537 ActionSet::kJumpContext); 00538 00539 QStringList::const_iterator it = m_sortedContexts.begin(); 00540 for (; it != m_sortedContexts.end(); ++it) 00541 { 00542 QString ctx_name = *it; 00543 ctx_name.detach(); 00544 QStringList actions = m_bindings->GetActions(ctx_name); 00545 actions.sort(); 00546 m_contexts.insert(ctx_name, actions); 00547 } 00548 } 00549 00556 void MythControls::DeleteKey(void) 00557 { 00558 QString context = GetCurrentContext(); 00559 QString key = GetCurrentKey(); 00560 QString action = GetCurrentAction(); 00561 00562 if (context.isEmpty() || key.isEmpty() || action.isEmpty()) 00563 { 00564 LOG(VB_GENERAL, LOG_ERR, 00565 "Unable to delete binding, missing information"); 00566 return; 00567 } 00568 00569 if (m_bindings->RemoveActionKey(context, action, key)) 00570 { 00571 RefreshKeyInformation(); 00572 return; 00573 } 00574 00575 QString label = tr("This action is mandatory and needs at least one key " 00576 "bound to it. Instead, try rebinding with another key."); 00577 00578 MythScreenStack *popupStack = 00579 GetMythMainWindow()->GetStack("popup stack"); 00580 00581 MythConfirmationDialog *confirmPopup = 00582 new MythConfirmationDialog(popupStack, label, false); 00583 00584 if (confirmPopup->Create()) 00585 { 00586 confirmPopup->SetReturnEvent(this, "mandatorydelete"); 00587 popupStack->AddScreen(confirmPopup); 00588 } 00589 else 00590 delete confirmPopup; 00591 } 00592 00597 void MythControls::ResolveConflict(ActionID *conflict, int error_level, 00598 const QString &key) 00599 { 00600 if (!conflict) 00601 return; 00602 00603 QString label = tr("This key binding conflicts with %1 in the %2 context.") 00604 .arg(conflict->GetAction()).arg(conflict->GetContext()); 00605 00606 bool error = (KeyBindings::kKeyBindingError == error_level); 00607 00608 if (error) 00609 label.append(tr(" Unable to bind key.")); 00610 else 00611 label.append(tr(" Do you want to bind it anyway?")); 00612 00613 MythScreenStack *popupStack = 00614 GetMythMainWindow()->GetStack("popup stack"); 00615 00616 MythConfirmationDialog *confirmPopup = 00617 new MythConfirmationDialog(popupStack, label, !error); 00618 00619 if (!error) 00620 { 00621 confirmPopup->SetData(qVariantFromValue(key)); 00622 confirmPopup->SetReturnEvent(this, "conflict"); 00623 } 00624 00625 if (confirmPopup->Create()) 00626 popupStack->AddScreen(confirmPopup); 00627 00628 delete conflict; 00629 } 00630 00631 void MythControls::GrabKey(void) 00632 { 00633 /* grab a key from the user */ 00634 MythScreenStack *popupStack = 00635 GetMythMainWindow()->GetStack("popup stack"); 00636 00637 KeyGrabPopupBox *keyGrabPopup = new KeyGrabPopupBox(popupStack); 00638 00639 if (keyGrabPopup->Create()) 00640 popupStack->AddScreen(keyGrabPopup, false); 00641 00642 connect(keyGrabPopup, SIGNAL(HaveResult(QString)), 00643 SLOT(AddKeyToAction(QString)), Qt::QueuedConnection); 00644 } 00645 00654 void MythControls::AddKeyToAction(QString key, bool ignoreconflict) 00655 { 00656 QString action = GetCurrentAction(); 00657 QString context = GetCurrentContext(); 00658 QStringList keys = m_bindings->GetActionKeys(context, action); 00659 00660 // Don't recreating an existing binding... 00661 int binding_index = GetCurrentButton(); 00662 if ((binding_index >= (int)Action::kMaximumNumberOfBindings) || 00663 ((binding_index < keys.size()) && (keys[binding_index] == key))) 00664 { 00665 return; 00666 } 00667 00668 if (!ignoreconflict) 00669 { 00670 // Check for first of the potential conflicts. 00671 int err_level; 00672 ActionID *conflict = m_bindings->GetConflict(context, key, err_level); 00673 if (conflict) 00674 { 00675 ResolveConflict(conflict, err_level, key); 00676 00677 return; 00678 } 00679 } 00680 00681 if (binding_index < keys.count()) 00682 m_bindings->ReplaceActionKey(context, action, key, 00683 keys[binding_index]); 00684 else 00685 m_bindings->AddActionKey(context, action, key); 00686 00687 RefreshKeyInformation(); 00688 } 00689 00690 void MythControls::customEvent(QEvent *event) 00691 { 00692 if (event->type() == DialogCompletionEvent::kEventType) 00693 { 00694 DialogCompletionEvent *dce = (DialogCompletionEvent*)(event); 00695 00696 QString resultid = dce->GetId(); 00697 int buttonnum = dce->GetResult(); 00698 00699 if (resultid == "action") 00700 { 00701 if (buttonnum == 0) 00702 GrabKey(); 00703 else if (buttonnum == 1) 00704 DeleteKey(); 00705 } 00706 else if (resultid == "option") 00707 { 00708 if (buttonnum == 0) 00709 Save(); 00710 else if (buttonnum == 1) 00711 ChangeView(); 00712 else if (buttonnum == 2) 00713 GetMythMainWindow()->JumpTo("Reset All Keys"); 00714 } 00715 else if (resultid == "exit") 00716 { 00717 if (buttonnum == 1) 00718 Save(); 00719 else 00720 Teardown(); 00721 00722 Close(); 00723 } 00724 else if (resultid == "view") 00725 { 00726 QStringList contents; 00727 QString leftcaption, rightcaption; 00728 00729 if (buttonnum == 0) 00730 { 00731 leftcaption = tr("Contexts"); 00732 rightcaption = tr("Actions"); 00733 m_currentView = kActionsByContext; 00734 contents = m_bindings->GetContexts(); 00735 } 00736 else if (buttonnum == 1) 00737 { 00738 leftcaption = tr("Contexts"); 00739 rightcaption = tr("Keys"); 00740 m_currentView = kKeysByContext; 00741 contents = m_bindings->GetContexts(); 00742 } 00743 else if (buttonnum == 2) 00744 { 00745 leftcaption = tr("Keys"); 00746 rightcaption = tr("Contexts"); 00747 m_currentView = kContextsByKey; 00748 contents = m_bindings->GetKeys(); 00749 } 00750 else 00751 return; 00752 00753 m_leftDescription->SetText(leftcaption); 00754 m_rightDescription->SetText(rightcaption); 00755 00756 SetListContents(m_leftList, contents, true); 00757 RefreshKeyInformation(); 00758 UpdateRightList(); 00759 00760 if (GetFocusWidget() != m_leftList) 00761 SetFocusWidget(m_leftList); 00762 } 00763 else if (resultid == "conflict") 00764 { 00765 if (buttonnum == 1) 00766 { 00767 QString key = dce->GetData().toString(); 00768 AddKeyToAction(key, true); 00769 } 00770 } 00771 00772 if (m_menuPopup) 00773 m_menuPopup = NULL; 00774 } 00775 00776 } 00777 00778 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1