|
MythTV
0.25-pre
|
00001 00002 #include "scheduleeditor.h" 00003 00004 // QT 00005 #include <QString> 00006 #include <QHash> 00007 #include <QCoreApplication> 00008 00009 // Libmyth 00010 #include "mythcorecontext.h" 00011 #include "storagegroup.h" 00012 #include "programtypes.h" 00013 00014 // Libmythtv 00015 #include "playgroup.h" 00016 #include "tv_play.h" 00017 #include "recordingprofile.h" 00018 #include "cardutil.h" 00019 00020 // Libmythui 00021 #include "mythmainwindow.h" 00022 #include "mythuihelper.h" 00023 #include "mythuibuttonlist.h" 00024 #include "mythuibutton.h" 00025 #include "mythuitext.h" 00026 #include "mythuistatetype.h" 00027 #include "mythuispinbox.h" 00028 #include "mythuicheckbox.h" 00029 #include "mythdialogbox.h" 00030 #include "mythprogressdialog.h" 00031 #include "mythuifilebrowser.h" 00032 #include "mythuimetadataresults.h" 00033 #include "mythuiimageresults.h" 00034 #include "videoutils.h" 00035 #include "mythuiutils.h" 00036 00037 #include "metadataimagehelper.h" 00038 00039 // Mythfrontend 00040 #include "proglist.h" 00041 #include "viewschedulediff.h" 00042 00043 #define ENUM_TO_QVARIANT(a) qVariantFromValue(static_cast<int>(a)) 00044 00045 // Define the strings inserted into the recordfilter table in the 00046 // database. This should make them available to the translators. 00047 static QString fs0(QT_TRANSLATE_NOOP("SchedFilterEditor", "New episode")); 00048 static QString fs1(QT_TRANSLATE_NOOP("SchedFilterEditor", "Identifiable episode")); 00049 static QString fs2(QT_TRANSLATE_NOOP("SchedFilterEditor", "First showing")); 00050 static QString fs3(QT_TRANSLATE_NOOP("SchedFilterEditor", "Prime time")); 00051 static QString fs4(QT_TRANSLATE_NOOP("SchedFilterEditor", "Commercial free")); 00052 static QString fs5(QT_TRANSLATE_NOOP("SchedFilterEditor", "High definition")); 00053 static QString fs6(QT_TRANSLATE_NOOP("SchedFilterEditor", "This episode")); 00054 static QString fs7(QT_TRANSLATE_NOOP("SchedFilterEditor", "This series")); 00055 00056 void *ScheduleEditor::RunScheduleEditor(ProgramInfo *proginfo, void *player) 00057 { 00058 RecordingRule *rule = new RecordingRule(); 00059 rule->LoadByProgram(proginfo); 00060 00061 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00062 ScheduleEditor *se = new ScheduleEditor(mainStack, rule, 00063 static_cast<TV*>(player)); 00064 00065 if (se->Create()) 00066 mainStack->AddScreen(se, (player == NULL)); 00067 else 00068 delete se; 00069 00070 return NULL; 00071 } 00072 00078 ScheduleEditor::ScheduleEditor(MythScreenStack *parent, 00079 RecordingInfo *recInfo, TV *player) 00080 : ScheduleCommon(parent, "ScheduleEditor"), 00081 m_recInfo(new RecordingInfo(*recInfo)), m_recordingRule(NULL), 00082 m_sendSig(false), 00083 m_saveButton(NULL), m_cancelButton(NULL), m_rulesList(NULL), 00084 m_schedOptButton(NULL), m_storeOptButton(NULL), 00085 m_postProcButton(NULL), m_schedInfoButton(NULL), 00086 m_previewButton(NULL), m_metadataButton(NULL), 00087 m_player(player) 00088 { 00089 m_recordingRule = new RecordingRule(); 00090 m_recordingRule->m_recordID = m_recInfo->GetRecordingRuleID(); 00091 } 00092 00093 ScheduleEditor::ScheduleEditor(MythScreenStack *parent, 00094 RecordingRule *recRule, TV *player) 00095 : ScheduleCommon(parent, "ScheduleEditor"), 00096 m_recInfo(NULL), m_recordingRule(recRule), 00097 m_sendSig(false), 00098 m_saveButton(NULL), m_cancelButton(NULL), m_rulesList(NULL), 00099 m_schedOptButton(NULL), m_storeOptButton(NULL), 00100 m_postProcButton(NULL), m_schedInfoButton(NULL), 00101 m_previewButton(NULL), m_metadataButton(NULL), 00102 m_player(player) 00103 { 00104 } 00105 00106 ScheduleEditor::~ScheduleEditor(void) 00107 { 00108 delete m_recordingRule; 00109 00110 // if we have a player, we need to tell we are done 00111 if (m_player) 00112 { 00113 QString message = QString("VIEWSCHEDULED_EXITING"); 00114 qApp->postEvent(m_player, new MythEvent(message)); 00115 } 00116 } 00117 00118 bool ScheduleEditor::Create() 00119 { 00120 if (!LoadWindowFromXML("schedule-ui.xml", "scheduleeditor", this)) 00121 return false; 00122 00123 bool err = false; 00124 00125 UIUtilE::Assign(this, m_rulesList, "rules", &err); 00126 00127 UIUtilE::Assign(this, m_schedOptButton, "schedoptions", &err); 00128 UIUtilE::Assign(this, m_storeOptButton, "storeoptions", &err); 00129 UIUtilE::Assign(this, m_postProcButton, "postprocessing", &err); 00130 UIUtilE::Assign(this, m_schedInfoButton, "schedinfo", &err); 00131 UIUtilE::Assign(this, m_previewButton, "preview", &err); 00132 UIUtilE::Assign(this, m_metadataButton, "metadata", &err); 00133 00134 UIUtilE::Assign(this, m_cancelButton, "cancel", &err); 00135 UIUtilE::Assign(this, m_saveButton, "save", &err); 00136 00137 if (err) 00138 { 00139 LOG(VB_GENERAL, LOG_ERR, "ScheduleEditor, theme is missing " 00140 "required elements"); 00141 return false; 00142 } 00143 00144 connect(m_rulesList, SIGNAL(itemSelected(MythUIButtonListItem *)), 00145 SLOT(RuleChanged(MythUIButtonListItem *))); 00146 00147 connect(m_schedOptButton, SIGNAL(Clicked()), SLOT(ShowSchedOpt())); 00148 connect(m_storeOptButton, SIGNAL(Clicked()), SLOT(ShowStoreOpt())); 00149 connect(m_postProcButton, SIGNAL(Clicked()), SLOT(ShowPostProc())); 00150 connect(m_schedInfoButton, SIGNAL(Clicked()), SLOT(ShowSchedInfo())); 00151 connect(m_previewButton, SIGNAL(Clicked()), SLOT(ShowPreview())); 00152 connect(m_metadataButton, SIGNAL(Clicked()), SLOT(ShowMetadataOptions())); 00153 00154 connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close())); 00155 connect(m_saveButton, SIGNAL(Clicked()), SLOT(Save())); 00156 00157 BuildFocusList(); 00158 00159 if (!m_recordingRule->IsLoaded()) 00160 { 00161 if (m_recInfo) 00162 m_recordingRule->LoadByProgram(m_recInfo); 00163 else if (m_recordingRule->m_recordID) 00164 m_recordingRule->Load(); 00165 00166 if (!m_recordingRule->IsLoaded()) 00167 { 00168 LOG(VB_GENERAL, LOG_ERR, 00169 "ScheduleEditor::Create() - Failed to load recording rule"); 00170 return false; 00171 } 00172 } 00173 00174 if (m_player) 00175 m_player->StartEmbedding(QRect()); 00176 00177 return true; 00178 } 00179 00180 void ScheduleEditor::Close() 00181 { 00182 // don't fade the screen if we are returning to the player 00183 if (m_player) 00184 GetScreenStack()->PopScreen(this, false); 00185 else 00186 GetScreenStack()->PopScreen(this, true); 00187 } 00188 00189 void ScheduleEditor::Load() 00190 { 00191 // Copy this now, it will change briefly after the first item is inserted 00192 // into the list by design of MythUIButtonList::itemSelected() 00193 RecordingType type = m_recordingRule->m_type; 00194 00195 // Rules List 00196 if (m_recordingRule->m_isOverride) 00197 { 00198 new MythUIButtonListItem(m_rulesList, 00199 tr("Record this showing with normal options"), 00200 ENUM_TO_QVARIANT(kNotRecording)); 00201 new MythUIButtonListItem(m_rulesList, 00202 tr("Record this showing with override options"), 00203 ENUM_TO_QVARIANT(kOverrideRecord)); 00204 new MythUIButtonListItem(m_rulesList, 00205 tr("Do not allow this showing to be recorded"), 00206 ENUM_TO_QVARIANT(kDontRecord)); 00207 } 00208 else 00209 { 00210 bool hasChannel = !m_recordingRule->m_station.isEmpty(); 00211 bool isManual = (m_recordingRule->m_searchType == kManualSearch); 00212 00213 new MythUIButtonListItem(m_rulesList, tr("Do not record this program"), 00214 ENUM_TO_QVARIANT(kNotRecording)); 00215 00216 if (hasChannel) 00217 new MythUIButtonListItem(m_rulesList, 00218 tr("Record only this showing"), 00219 ENUM_TO_QVARIANT(kSingleRecord)); 00220 if (!isManual) 00221 new MythUIButtonListItem(m_rulesList, 00222 tr("Record one showing of this title"), 00223 ENUM_TO_QVARIANT(kFindOneRecord)); 00224 if (hasChannel) 00225 new MythUIButtonListItem(m_rulesList, 00226 tr("Record in this timeslot every week"), 00227 ENUM_TO_QVARIANT(kWeekslotRecord)); 00228 if (!isManual) 00229 new MythUIButtonListItem(m_rulesList, 00230 tr("Record one showing of this title every week"), 00231 ENUM_TO_QVARIANT(kFindWeeklyRecord)); 00232 if (hasChannel) 00233 new MythUIButtonListItem(m_rulesList, 00234 tr("Record in this timeslot every day"), 00235 ENUM_TO_QVARIANT(kTimeslotRecord)); 00236 if (!isManual) 00237 new MythUIButtonListItem(m_rulesList, 00238 tr("Record one showing of this title every day"), 00239 ENUM_TO_QVARIANT(kFindDailyRecord)); 00240 if (hasChannel && !isManual) 00241 new MythUIButtonListItem(m_rulesList, 00242 tr("Record at any time on this channel"), 00243 ENUM_TO_QVARIANT(kChannelRecord)); 00244 if (!isManual) 00245 new MythUIButtonListItem(m_rulesList, 00246 tr("Record at any time on any channel"), 00247 ENUM_TO_QVARIANT(kAllRecord)); 00248 } 00249 m_rulesList->SetValueByData(ENUM_TO_QVARIANT(type)); 00250 00251 InfoMap progMap; 00252 if (m_recInfo) 00253 m_recInfo->ToMap(progMap); 00254 else 00255 m_recordingRule->ToMap(progMap); 00256 00257 switch (m_recordingRule->m_searchType) 00258 { 00259 case kPowerSearch: 00260 progMap["searchType"] = tr("Power Search"); 00261 break; 00262 case kTitleSearch: 00263 progMap["searchType"] = tr("Title Search"); 00264 break; 00265 case kKeywordSearch: 00266 progMap["searchType"] = tr("Keyword Search"); 00267 break; 00268 case kPeopleSearch: 00269 progMap["searchType"] = tr("People Search"); 00270 break; 00271 default: 00272 progMap["searchType"] = tr("Unknown Search"); 00273 break; 00274 } 00275 00276 SetTextFromMap(progMap); 00277 } 00278 00279 void ScheduleEditor::RuleChanged(MythUIButtonListItem *item) 00280 { 00281 if (!item) 00282 return; 00283 00284 RecordingType type = static_cast<RecordingType>(item->GetData().toInt()); 00285 00286 bool isScheduled = (type != kNotRecording); 00287 00288 m_schedOptButton->SetEnabled(isScheduled); 00289 m_storeOptButton->SetEnabled(isScheduled); 00290 m_postProcButton->SetEnabled(isScheduled); 00291 00292 m_recordingRule->m_type = type; 00293 } 00294 00295 void ScheduleEditor::Save() 00296 { 00297 MythUIButtonListItem *item = m_rulesList->GetItemCurrent(); 00298 if (item) 00299 { 00300 RecordingType type = static_cast<RecordingType>(item->GetData().toInt()); 00301 if (type == kNotRecording) 00302 { 00303 DeleteRule(); 00304 Close(); 00305 return; 00306 } 00307 else 00308 m_recordingRule->m_type = type; 00309 } 00310 00311 m_recordingRule->Save(true); 00312 emit ruleSaved(m_recordingRule->m_recordID); 00313 Close(); 00314 } 00315 00316 void ScheduleEditor::DeleteRule() 00317 { 00318 m_recordingRule->Delete(); 00319 } 00320 00321 void ScheduleEditor::ShowSchedOpt() 00322 { 00323 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00324 SchedOptEditor *schedoptedit = new SchedOptEditor(mainStack, m_recInfo, 00325 m_recordingRule); 00326 if (schedoptedit->Create()) 00327 mainStack->AddScreen(schedoptedit); 00328 else 00329 delete schedoptedit; 00330 } 00331 00332 void ScheduleEditor::ShowStoreOpt() 00333 { 00334 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00335 StoreOptEditor *storeoptedit = new StoreOptEditor(mainStack, m_recInfo, 00336 m_recordingRule); 00337 if (storeoptedit->Create()) 00338 mainStack->AddScreen(storeoptedit); 00339 else 00340 delete storeoptedit; 00341 } 00342 00343 void ScheduleEditor::ShowPostProc() 00344 { 00345 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00346 PostProcEditor *ppedit = new PostProcEditor(mainStack, m_recInfo, 00347 m_recordingRule); 00348 if (ppedit->Create()) 00349 mainStack->AddScreen(ppedit); 00350 else 00351 delete ppedit; 00352 } 00353 00354 void ScheduleEditor::ShowSchedInfo() 00355 { 00356 QString label = tr("Schedule Information"); 00357 00358 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 00359 MythDialogBox *menuPopup = new MythDialogBox(label, popupStack, "menuPopup"); 00360 00361 if (menuPopup->Create()) 00362 { 00363 menuPopup->SetReturnEvent(this, "schedinfo"); 00364 00365 menuPopup->AddButton(tr("Program Details")); 00366 menuPopup->AddButton(tr("Upcoming episodes")); 00367 menuPopup->AddButton(tr("Upcoming recordings")); 00368 menuPopup->AddButton(tr("Previously scheduled")); 00369 00370 popupStack->AddScreen(menuPopup); 00371 } 00372 else 00373 delete menuPopup; 00374 } 00375 00376 void ScheduleEditor::customEvent(QEvent *event) 00377 { 00378 if (event->type() == DialogCompletionEvent::kEventType) 00379 { 00380 DialogCompletionEvent *dce = (DialogCompletionEvent*)(event); 00381 00382 QString resultid = dce->GetId(); 00383 int buttonnum = dce->GetResult(); 00384 00385 if (resultid == "schedinfo") 00386 { 00387 switch (buttonnum) 00388 { 00389 case 0 : 00390 if (m_recInfo) 00391 ShowDetails(m_recInfo); 00392 break; 00393 case 1 : 00394 showUpcomingByTitle(); 00395 break; 00396 case 2 : 00397 showUpcomingByRule(); 00398 break; 00399 case 3 : 00400 showPrevious(); 00401 break; 00402 } 00403 } 00404 } 00405 } 00406 00407 void ScheduleEditor::showPrevious(void) 00408 { 00409 QString title; 00410 if (m_recInfo) 00411 title = m_recInfo->GetTitle(); 00412 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00413 ProgLister *pl = new ProgLister(mainStack, m_recordingRule->m_recordID, 00414 title); 00415 if (pl->Create()) 00416 mainStack->AddScreen(pl); 00417 else 00418 delete pl; 00419 } 00420 00421 void ScheduleEditor::showUpcomingByRule(void) 00422 { 00423 // No rule? Search by title 00424 if (m_recordingRule->m_recordID <= 0) 00425 { 00426 showUpcomingByTitle(); 00427 return; 00428 } 00429 00430 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00431 ProgLister *pl = new ProgLister(mainStack, plRecordid, 00432 QString::number(m_recordingRule->m_recordID), 00433 ""); 00434 00435 if (pl->Create()) 00436 mainStack->AddScreen(pl); 00437 else 00438 delete pl; 00439 } 00440 00441 void ScheduleEditor::showUpcomingByTitle(void) 00442 { 00443 QString title = m_recordingRule->m_title; 00444 00445 if (m_recordingRule->m_searchType != kNoSearch) 00446 title.remove(QRegExp(" \\(.*\\)$")); 00447 00448 ShowUpcoming(title, m_recordingRule->m_seriesid); 00449 } 00450 00451 void ScheduleEditor::ShowPreview(void) 00452 { 00453 QString ttable = "record_tmp"; 00454 m_recordingRule->UseTempTable(true, ttable); 00455 00456 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00457 ViewScheduleDiff *vsd = new ViewScheduleDiff(mainStack, ttable, 00458 m_recordingRule->m_tempID, 00459 m_recordingRule->m_title); 00460 if (vsd->Create()) 00461 mainStack->AddScreen(vsd); 00462 else 00463 delete vsd; 00464 00465 m_recordingRule->UseTempTable(false); 00466 } 00467 00468 void ScheduleEditor::ShowMetadataOptions(void) 00469 { 00470 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00471 MetadataOptions *rad = new MetadataOptions(mainStack, m_recInfo, 00472 m_recordingRule); 00473 if (rad->Create()) 00474 mainStack->AddScreen(rad); 00475 else 00476 delete rad; 00477 } 00478 00480 00486 SchedOptEditor::SchedOptEditor(MythScreenStack *parent, 00487 RecordingInfo *recInfo, 00488 RecordingRule *rule) 00489 : MythScreenType(parent, "ScheduleOptionsEditor"), 00490 m_recInfo(NULL), m_recordingRule(rule), 00491 m_backButton(NULL), 00492 m_prioritySpin(NULL), m_inputList(NULL), m_startoffsetSpin(NULL), 00493 m_endoffsetSpin(NULL), m_dupmethodList(NULL), m_dupscopeList(NULL), 00494 m_filtersButton(NULL), m_ruleactiveCheck(NULL) 00495 { 00496 if (recInfo) 00497 m_recInfo = new RecordingInfo(*recInfo); 00498 } 00499 00500 SchedOptEditor::~SchedOptEditor(void) 00501 { 00502 } 00503 00504 bool SchedOptEditor::Create() 00505 { 00506 if (!LoadWindowFromXML("schedule-ui.xml", "scheduleoptionseditor", this)) 00507 return false; 00508 00509 bool err = false; 00510 00511 UIUtilE::Assign(this, m_prioritySpin, "priority", &err); 00512 UIUtilE::Assign(this, m_inputList, "input", &err); 00513 UIUtilE::Assign(this, m_startoffsetSpin, "startoffset", &err); 00514 UIUtilE::Assign(this, m_endoffsetSpin, "endoffset", &err); 00515 UIUtilE::Assign(this, m_dupmethodList, "dupmethod", &err); 00516 UIUtilE::Assign(this, m_dupscopeList, "dupscope", &err); 00517 00518 UIUtilW::Assign(this, m_filtersButton, "filters"); 00519 UIUtilW::Assign(this, m_backButton, "back"); 00520 00521 UIUtilE::Assign(this, m_ruleactiveCheck, "ruleactive", &err); 00522 00523 if (err) 00524 { 00525 LOG(VB_GENERAL, LOG_ERR, "SchedOptEditor, theme is missing " 00526 "required elements"); 00527 return false; 00528 } 00529 00530 if (m_backButton) 00531 connect(m_backButton, SIGNAL(Clicked()), SLOT(Close())); 00532 00533 if (m_filtersButton && m_recordingRule->m_type == kOverrideRecord) 00534 m_filtersButton->SetEnabled(false); 00535 if (m_recordingRule->m_type == kSingleRecord || 00536 m_recordingRule->m_type == kOverrideRecord) 00537 { 00538 m_dupmethodList->SetEnabled(false); 00539 m_dupscopeList->SetEnabled(false); 00540 } 00541 00542 connect(m_dupmethodList, SIGNAL(itemSelected(MythUIButtonListItem *)), 00543 SLOT(dupMatchChanged(MythUIButtonListItem *))); 00544 00545 if (m_filtersButton) 00546 connect(m_filtersButton, SIGNAL(Clicked()), SLOT(ShowFilters())); 00547 00548 BuildFocusList(); 00549 00550 return true; 00551 } 00552 00553 void SchedOptEditor::Load() 00554 { 00555 MSqlQuery query(MSqlQuery::InitCon()); 00556 00557 // Priority 00558 m_prioritySpin->SetRange(-99,99,1,5); 00559 m_prioritySpin->SetValue(m_recordingRule->m_recPriority); 00560 00561 // Preferred Input 00562 new MythUIButtonListItem(m_inputList, tr("Use any available input"), 00563 qVariantFromValue(0)); 00564 00565 vector<uint> inputids = CardUtil::GetInputIDs(0); 00566 for (uint i = 0; i < inputids.size(); ++i) 00567 { 00568 new MythUIButtonListItem(m_inputList, tr("Prefer input %1") 00569 .arg(CardUtil::GetDisplayName(inputids[i])) 00570 .arg(inputids[i])); 00571 } 00572 00573 m_inputList->SetValueByData(m_recordingRule->m_prefInput); 00574 00575 // Start Offset 00576 m_startoffsetSpin->SetRange(480,-480,1,10); 00577 m_startoffsetSpin->SetValue(m_recordingRule->m_startOffset); 00578 00579 // End Offset 00580 m_endoffsetSpin->SetRange(-480,480,1,10); 00581 m_endoffsetSpin->SetValue(m_recordingRule->m_endOffset); 00582 00583 // Duplicate Match Type 00584 new MythUIButtonListItem(m_dupmethodList, 00585 tr("Match duplicates using subtitle & " 00586 "description"), 00587 ENUM_TO_QVARIANT(kDupCheckSubDesc)); 00588 new MythUIButtonListItem(m_dupmethodList, 00589 tr("Match duplicates using subtitle then " 00590 "description"), 00591 ENUM_TO_QVARIANT(kDupCheckSubThenDesc)); 00592 new MythUIButtonListItem(m_dupmethodList, 00593 tr("Match duplicates using subtitle"), 00594 ENUM_TO_QVARIANT(kDupCheckSub)); 00595 new MythUIButtonListItem(m_dupmethodList, 00596 tr("Match duplicates using description"), 00597 ENUM_TO_QVARIANT(kDupCheckDesc)); 00598 new MythUIButtonListItem(m_dupmethodList, 00599 tr("Don't match duplicates"), 00600 ENUM_TO_QVARIANT(kDupCheckNone)); 00601 00602 m_dupmethodList->SetValueByData( 00603 ENUM_TO_QVARIANT(m_recordingRule->m_dupMethod)); 00604 00605 // Duplicate Matching Scope 00606 new MythUIButtonListItem(m_dupscopeList, 00607 tr("Look for duplicates in current and previous " 00608 "recordings"), 00609 ENUM_TO_QVARIANT(kDupsInAll)); 00610 new MythUIButtonListItem(m_dupscopeList, 00611 tr("Look for duplicates in current recordings " 00612 "only"), 00613 ENUM_TO_QVARIANT(kDupsInRecorded)); 00614 new MythUIButtonListItem(m_dupscopeList, 00615 tr("Look for duplicates in previous recordings " 00616 "only"), 00617 ENUM_TO_QVARIANT(kDupsInOldRecorded)); 00618 00619 if (gCoreContext->GetNumSetting("HaveRepeats", 0)) 00620 { 00621 new MythUIButtonListItem(m_dupscopeList, 00622 tr("Record new episodes only"), 00623 ENUM_TO_QVARIANT(kDupsNewEpi | kDupsInAll)); 00624 } 00625 00626 m_dupscopeList->SetValueByData(ENUM_TO_QVARIANT(m_recordingRule->m_dupIn)); 00627 00628 // Active/Disabled 00629 m_ruleactiveCheck->SetCheckState(!m_recordingRule->m_isInactive); 00630 00631 InfoMap progMap; 00632 if (m_recInfo) 00633 m_recInfo->ToMap(progMap); 00634 else 00635 m_recordingRule->ToMap(progMap); 00636 SetTextFromMap(progMap); 00637 } 00638 00639 void SchedOptEditor::dupMatchChanged(MythUIButtonListItem *item) 00640 { 00641 if (!item) 00642 return; 00643 00644 int dupMethod = item->GetData().toInt(); 00645 00646 if (dupMethod <= 0) 00647 m_dupscopeList->SetEnabled(false); 00648 else 00649 m_dupscopeList->SetEnabled(true); 00650 } 00651 00652 void SchedOptEditor::Save() 00653 { 00654 // Priority 00655 m_recordingRule->m_recPriority = m_prioritySpin->GetIntValue(); 00656 00657 // Preferred Input 00658 m_recordingRule->m_prefInput = m_inputList->GetDataValue().toInt(); 00659 00660 // Start Offset 00661 m_recordingRule->m_startOffset = m_startoffsetSpin->GetIntValue(); 00662 00663 // End Offset 00664 m_recordingRule->m_endOffset = m_endoffsetSpin->GetIntValue(); 00665 00666 // Duplicate Match Type 00667 m_recordingRule->m_dupMethod = static_cast<RecordingDupMethodType> 00668 (m_dupmethodList->GetDataValue().toInt()); 00669 00670 // Duplicate Matching Scope 00671 m_recordingRule->m_dupIn = static_cast<RecordingDupInType> 00672 (m_dupscopeList->GetDataValue().toInt()); 00673 00674 // Active/Disabled 00675 m_recordingRule->m_isInactive = (!m_ruleactiveCheck->GetBooleanCheckState()); 00676 } 00677 00678 void SchedOptEditor::Close() 00679 { 00680 Save(); 00681 MythScreenType::Close(); 00682 } 00683 00684 void SchedOptEditor::ShowFilters(void) 00685 { 00686 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 00687 SchedFilterEditor *schedfilteredit = new SchedFilterEditor(mainStack, 00688 m_recInfo, 00689 m_recordingRule); 00690 if (schedfilteredit->Create()) 00691 mainStack->AddScreen(schedfilteredit); 00692 else 00693 delete schedfilteredit; 00694 } 00695 00697 00703 SchedFilterEditor::SchedFilterEditor(MythScreenStack *parent, 00704 RecordingInfo *recInfo, 00705 RecordingRule *rule) 00706 : MythScreenType(parent, "ScheduleFilterEditor"), 00707 m_recInfo(NULL), m_recordingRule(rule), 00708 m_backButton(NULL), m_filtersList(NULL) 00709 { 00710 if (recInfo) 00711 m_recInfo = new RecordingInfo(*recInfo); 00712 } 00713 00714 SchedFilterEditor::~SchedFilterEditor(void) 00715 { 00716 } 00717 00718 bool SchedFilterEditor::Create() 00719 { 00720 if (!LoadWindowFromXML("schedule-ui.xml", "schedulefiltereditor", this)) 00721 return false; 00722 00723 bool err = false; 00724 00725 UIUtilE::Assign(this, m_filtersList, "filters", &err); 00726 UIUtilW::Assign(this, m_backButton, "back"); 00727 00728 if (err) 00729 { 00730 LOG(VB_GENERAL, LOG_ERR, "SchedFilterEditor, theme is missing " 00731 "required elements"); 00732 return false; 00733 } 00734 00735 if (m_backButton) 00736 connect(m_backButton, SIGNAL(Clicked()), SLOT(Close())); 00737 00738 connect(m_filtersList, SIGNAL(itemClicked(MythUIButtonListItem *)), 00739 SLOT(ToggleSelected(MythUIButtonListItem *))); 00740 BuildFocusList(); 00741 00742 return true; 00743 } 00744 00745 void SchedFilterEditor::Load() 00746 { 00747 MSqlQuery query(MSqlQuery::InitCon()); 00748 00749 query.prepare("SELECT filterid, description, newruledefault " 00750 "FROM recordfilter ORDER BY filterid"); 00751 00752 if (query.exec()) 00753 { 00754 MythUIButtonListItem *button; 00755 00756 while (query.next()) 00757 { 00758 uint32_t filterid = query.value(0).toInt(); 00759 QString description = tr(query.value(1).toString() 00760 .toUtf8().constData()); 00761 // bool filter_default = query.value(2).toInt(); 00762 00763 // Fill in list of possible filters 00764 button = new MythUIButtonListItem(m_filtersList, description, 00765 filterid); 00766 button->setCheckable(true); 00767 button->setChecked(m_recordingRule->m_filter & (1 << filterid) ? 00768 MythUIButtonListItem::FullChecked : 00769 MythUIButtonListItem::NotChecked); 00770 } 00771 } 00772 00773 InfoMap progMap; 00774 if (m_recInfo) 00775 m_recInfo->ToMap(progMap); 00776 else 00777 m_recordingRule->ToMap(progMap); 00778 SetTextFromMap(progMap); 00779 } 00780 00781 void SchedFilterEditor::ToggleSelected(MythUIButtonListItem *item) 00782 { 00783 item->setChecked(item->state() == MythUIButtonListItem::FullChecked ? 00784 MythUIButtonListItem::NotChecked : 00785 MythUIButtonListItem::FullChecked); 00786 } 00787 00788 void SchedFilterEditor::Save() 00789 { 00790 // Iterate through button list, and build the mask 00791 MythUIButtonListItem *button; 00792 uint32_t filter_mask = 0; 00793 int idx, end; 00794 00795 end = m_filtersList->GetCount(); 00796 for (idx = 0; idx < end; ++idx) 00797 { 00798 if ((button = m_filtersList->GetItemAt(idx)) && 00799 button->state() == MythUIButtonListItem::FullChecked) 00800 filter_mask |= (1 << qVariantValue<uint32_t>(button->GetData())); 00801 } 00802 m_recordingRule->m_filter = filter_mask; 00803 } 00804 00805 void SchedFilterEditor::Close() 00806 { 00807 Save(); 00808 MythScreenType::Close(); 00809 } 00810 00812 00818 StoreOptEditor::StoreOptEditor(MythScreenStack *parent, 00819 RecordingInfo *recInfo, 00820 RecordingRule *rule) 00821 : MythScreenType(parent, "StorageOptionsEditor"), 00822 m_recInfo(NULL), m_recordingRule(rule), 00823 m_backButton(NULL), 00824 m_recprofileList(NULL), m_recgroupList(NULL), 00825 m_storagegroupList(NULL), m_playgroupList(NULL), 00826 m_autoexpireCheck(NULL), m_maxepSpin(NULL), m_maxbehaviourList(NULL) 00827 { 00828 if (recInfo) 00829 m_recInfo = new RecordingInfo(*recInfo); 00830 } 00831 00832 StoreOptEditor::~StoreOptEditor(void) 00833 { 00834 } 00835 00836 bool StoreOptEditor::Create() 00837 { 00838 if (!LoadWindowFromXML("schedule-ui.xml", "storageoptionseditor", this)) 00839 return false; 00840 00841 bool err = false; 00842 00843 UIUtilE::Assign(this, m_recprofileList, "recprofile", &err); 00844 UIUtilE::Assign(this, m_recgroupList, "recgroup", &err); 00845 UIUtilE::Assign(this, m_storagegroupList, "storagegroup", &err); 00846 UIUtilE::Assign(this, m_playgroupList, "playgroup", &err); 00847 UIUtilE::Assign(this, m_maxepSpin, "maxepisodes", &err); 00848 UIUtilE::Assign(this, m_maxbehaviourList, "maxnewest", &err); 00849 00850 UIUtilE::Assign(this, m_autoexpireCheck, "autoexpire", &err); 00851 UIUtilW::Assign(this, m_backButton, "back"); 00852 00853 if (err) 00854 { 00855 LOG(VB_GENERAL, LOG_ERR, "StoreOptEditor, theme is missing " 00856 "required elements"); 00857 return false; 00858 } 00859 00860 if (m_backButton) 00861 connect(m_backButton, SIGNAL(Clicked()), SLOT(Close())); 00862 00863 connect(m_maxepSpin, SIGNAL(itemSelected(MythUIButtonListItem *)), 00864 SLOT(maxEpChanged(MythUIButtonListItem *))); 00865 00866 connect(m_recgroupList, SIGNAL(LosingFocus()), 00867 SLOT(PromptForRecgroup())); 00868 00869 BuildFocusList(); 00870 00871 return true; 00872 } 00873 00874 void StoreOptEditor::Load() 00875 { 00876 MSqlQuery query(MSqlQuery::InitCon()); 00877 00878 // Recording Profile 00879 QString label = tr("Record using the %1 profile"); 00880 QMap<int, QString> profiles = RecordingProfile::listProfiles(0); 00881 QMap<int, QString>::iterator pit; 00882 for (pit = profiles.begin(); pit != profiles.end(); ++pit) 00883 { 00884 new MythUIButtonListItem(m_recprofileList, label.arg(pit.value()), 00885 qVariantFromValue(pit.value())); 00886 } 00887 m_recprofileList->SetValueByData(m_recordingRule->m_recProfile); 00888 00889 // Recording Group 00890 QStringList groups; 00891 QStringList::Iterator it; 00892 QString value, dispValue; 00893 bool foundDefault = false; 00894 00895 // Count the ways the following is _wrong_ 00896 00897 new MythUIButtonListItem(m_recgroupList, 00898 tr("Create a new recording group"), 00899 qVariantFromValue(QString("__NEW_GROUP__"))); 00900 00901 query.prepare("SELECT DISTINCT recgroup FROM recorded"); 00902 if (query.exec()) 00903 { 00904 while (query.next()) 00905 { 00906 value = query.value(0).toString(); 00907 00908 if (value != "Deleted") 00909 { 00910 groups += value; 00911 if (value == "Default") 00912 foundDefault = true; 00913 } 00914 } 00915 } 00916 00917 query.prepare("SELECT DISTINCT recgroup FROM record"); 00918 if (query.exec()) 00919 { 00920 while (query.next()) 00921 { 00922 value = query.value(0).toString(); 00923 groups += value; 00924 00925 if (value == "Default") 00926 foundDefault = true; 00927 } 00928 } 00929 00930 groups.sort(); 00931 groups.removeDuplicates(); 00932 for (it = groups.begin(); it != groups.end(); ++it) 00933 { 00934 label = tr("Include in the \"%1\" recording group"); 00935 if (!foundDefault && *it > tr("Default")) 00936 { 00937 new MythUIButtonListItem(m_recgroupList, label.arg(tr("Default")), 00938 qVariantFromValue(QString("Default"))); 00939 foundDefault = true; 00940 } 00941 00942 if (*it == "Default") 00943 dispValue = tr("Default"); 00944 else 00945 dispValue = *it; 00946 00947 new MythUIButtonListItem(m_recgroupList, label.arg(dispValue), 00948 qVariantFromValue(*it)); 00949 } 00950 00951 m_recgroupList->SetValueByData(m_recordingRule->m_recGroup); 00952 00953 // Storage Group 00954 groups = StorageGroup::getRecordingsGroups(); 00955 foundDefault = false; 00956 for (it = groups.begin(); it != groups.end(); ++it) 00957 { 00958 if (*it == "Default") 00959 foundDefault = true; 00960 } 00961 00962 for (it = groups.begin(); it != groups.end(); ++it) 00963 { 00964 label = tr("Store in the \"%1\" storage group"); 00965 if (!foundDefault && *it > tr("Default")) 00966 { 00967 new MythUIButtonListItem(m_storagegroupList, 00968 label.arg(tr("Default")), 00969 qVariantFromValue(QString("Default"))); 00970 foundDefault = true; 00971 } 00972 00973 if (*it == "Default") 00974 dispValue = tr("Default"); 00975 else if (*it == "LiveTV") 00976 dispValue = tr("Live TV"); 00977 else 00978 dispValue = *it; 00979 00980 new MythUIButtonListItem(m_storagegroupList, label.arg(dispValue), 00981 qVariantFromValue(*it)); 00982 } 00983 00984 m_storagegroupList->SetValueByData(m_recordingRule->m_storageGroup); 00985 00986 // Playback Group 00987 label = tr("Use \"%1\" playback group settings"); 00988 new MythUIButtonListItem(m_playgroupList, label.arg(tr("Default")), 00989 qVariantFromValue(QString("Default"))); 00990 00991 groups = PlayGroup::GetNames(); 00992 00993 for (it = groups.begin(); it != groups.end(); ++it) 00994 { 00995 new MythUIButtonListItem(m_playgroupList, label.arg(*it), 00996 qVariantFromValue(*it)); 00997 } 00998 00999 m_playgroupList->SetValueByData(m_recordingRule->m_playGroup); 01000 01001 // Auto-Expire 01002 m_autoexpireCheck->SetCheckState(m_recordingRule->m_autoExpire); 01003 01004 // Max Episodes 01005 m_maxepSpin->SetRange(0,100,1,5); 01006 m_maxepSpin->SetValue(m_recordingRule->m_maxEpisodes); 01007 01008 // Max Episode Behaviour 01009 new MythUIButtonListItem(m_maxbehaviourList, 01010 tr("Don't record if this would exceed the max " 01011 "episodes"), qVariantFromValue(false)); 01012 new MythUIButtonListItem(m_maxbehaviourList, 01013 tr("Delete oldest if this would exceed the max " 01014 "episodes"), qVariantFromValue(true)); 01015 m_maxbehaviourList->SetValueByData(m_recordingRule->m_maxNewest); 01016 01017 01018 InfoMap progMap; 01019 if (m_recInfo) 01020 m_recInfo->ToMap(progMap); 01021 else 01022 m_recordingRule->ToMap(progMap); 01023 SetTextFromMap(progMap); 01024 } 01025 01026 void StoreOptEditor::maxEpChanged(MythUIButtonListItem *item) 01027 { 01028 if (!item) 01029 return; 01030 01031 if (item->GetData().toInt() == 0) 01032 m_maxbehaviourList->SetEnabled(false); 01033 else 01034 m_maxbehaviourList->SetEnabled(true); 01035 } 01036 01037 void StoreOptEditor::PromptForRecgroup() 01038 { 01039 if (m_recgroupList->GetDataValue().toString() != "__NEW_GROUP__") 01040 return; 01041 01042 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); 01043 01044 QString label = tr("Create New Recording Group. Enter group name: "); 01045 01046 MythTextInputDialog *textDialog = new MythTextInputDialog(popupStack, label, 01047 static_cast<InputFilter>(FilterSymbols | FilterPunct)); 01048 01049 textDialog->SetReturnEvent(this, "newrecgroup"); 01050 01051 if (textDialog->Create()) 01052 popupStack->AddScreen(textDialog, false); 01053 return; 01054 } 01055 01056 void StoreOptEditor::customEvent(QEvent *event) 01057 { 01058 if (event->type() == DialogCompletionEvent::kEventType) 01059 { 01060 DialogCompletionEvent *dce = (DialogCompletionEvent*)(event); 01061 01062 QString resultid = dce->GetId(); 01063 QString resulttext = dce->GetResultText(); 01064 01065 if (resultid == "newrecgroup") 01066 { 01067 if (!resulttext.isEmpty()) 01068 { 01069 QString label = tr("Include in the \"%1\" recording group"); 01070 MythUIButtonListItem *item = 01071 new MythUIButtonListItem(m_recgroupList, 01072 label.arg(resulttext), 01073 qVariantFromValue(resulttext)); 01074 m_recgroupList->SetItemCurrent(item); 01075 } 01076 else 01077 m_recgroupList->SetValueByData(m_recordingRule->m_recGroup); 01078 } 01079 } 01080 } 01081 01082 void StoreOptEditor::Save() 01083 { 01084 // If the user has selected 'Create a new regroup' but failed to enter a 01085 // name when prompted, restore the original value 01086 if (m_recgroupList->GetDataValue().toString() == "__NEW_GROUP__") 01087 m_recgroupList->SetValueByData(m_recordingRule->m_recGroup); 01088 01089 // Recording Profile 01090 m_recordingRule->m_recProfile = m_recprofileList->GetDataValue().toString(); 01091 01092 // Recording Group 01093 m_recordingRule->m_recGroup = m_recgroupList->GetDataValue().toString(); 01094 01095 // Storage Group 01096 m_recordingRule->m_storageGroup = m_storagegroupList->GetDataValue() 01097 .toString(); 01098 01099 // Playback Group 01100 m_recordingRule->m_playGroup = m_playgroupList->GetDataValue().toString(); 01101 01102 // Auto-Expire 01103 m_recordingRule->m_autoExpire = m_autoexpireCheck->GetBooleanCheckState(); 01104 01105 // Max Episodes 01106 m_recordingRule->m_maxEpisodes = m_maxepSpin->GetIntValue(); 01107 01108 // Max Episode Behaviour 01109 m_recordingRule->m_maxNewest = m_maxbehaviourList->GetDataValue().toBool(); 01110 } 01111 01112 void StoreOptEditor::Close() 01113 { 01114 Save(); 01115 MythScreenType::Close(); 01116 } 01117 01119 01125 PostProcEditor::PostProcEditor(MythScreenStack *parent, 01126 RecordingInfo *recInfo, 01127 RecordingRule *rule) 01128 : MythScreenType(parent, "PostProcOptionsEditor"), 01129 m_recInfo(NULL), m_recordingRule(rule), 01130 m_backButton(NULL), 01131 m_commflagCheck(NULL), m_transcodeCheck(NULL), 01132 m_transcodeprofileList(NULL), m_userjob1Check(NULL), 01133 m_userjob2Check(NULL), m_userjob3Check(NULL), 01134 m_userjob4Check(NULL), m_metadataLookupCheck(NULL) 01135 { 01136 if (recInfo) 01137 m_recInfo = new RecordingInfo(*recInfo); 01138 } 01139 01140 PostProcEditor::~PostProcEditor(void) 01141 { 01142 } 01143 01144 bool PostProcEditor::Create() 01145 { 01146 if (!LoadWindowFromXML("schedule-ui.xml", "postproceditor", this)) 01147 return false; 01148 01149 bool err = false; 01150 01151 UIUtilE::Assign(this, m_commflagCheck, "autocommflag", &err); 01152 UIUtilE::Assign(this, m_transcodeCheck, "autotranscode", &err); 01153 UIUtilE::Assign(this, m_transcodeprofileList, "transcodeprofile", &err); 01154 UIUtilE::Assign(this, m_userjob1Check, "userjob1", &err); 01155 UIUtilE::Assign(this, m_userjob2Check, "userjob2", &err); 01156 UIUtilE::Assign(this, m_userjob3Check, "userjob3", &err); 01157 UIUtilE::Assign(this, m_userjob4Check, "userjob4", &err); 01158 UIUtilW::Assign(this, m_metadataLookupCheck, "metadatalookup"); 01159 UIUtilW::Assign(this, m_backButton, "back"); 01160 01161 if (err) 01162 { 01163 LOG(VB_GENERAL, LOG_ERR, "PostProcEditor, theme is missing " 01164 "required elements"); 01165 return false; 01166 } 01167 01168 if (m_backButton) 01169 connect(m_backButton, SIGNAL(Clicked()), SLOT(Close())); 01170 01171 connect(m_transcodeCheck, SIGNAL(toggled(bool)), 01172 SLOT(transcodeEnable(bool))); 01173 01174 BuildFocusList(); 01175 01176 return true; 01177 } 01178 01179 void PostProcEditor::Load() 01180 { 01181 // Auto-commflag 01182 m_commflagCheck->SetCheckState(m_recordingRule->m_autoCommFlag); 01183 01184 // Auto-transcode 01185 m_transcodeCheck->SetCheckState(m_recordingRule->m_autoTranscode); 01186 01187 // Transcode Method 01188 QMap<int, QString> profiles = RecordingProfile::listProfiles( 01189 RecordingProfile::TranscoderGroup); 01190 QMap<int, QString>::iterator it; 01191 for (it = profiles.begin(); it != profiles.end(); ++it) 01192 { 01193 new MythUIButtonListItem(m_transcodeprofileList, it.value(), 01194 qVariantFromValue(it.key())); 01195 } 01196 m_transcodeprofileList->SetValueByData(m_recordingRule->m_transcoder); 01197 01198 // User Job #1 01199 m_userjob1Check->SetCheckState(m_recordingRule->m_autoUserJob1); 01200 MythUIText *userjob1Text = NULL; 01201 UIUtilW::Assign(this, userjob1Text, "userjob1text"); 01202 if (userjob1Text) 01203 userjob1Text->SetText(tr("Run '%1'") 01204 .arg(gCoreContext->GetSetting("UserJobDesc1"), "User Job 1")); 01205 01206 // User Job #2 01207 m_userjob2Check->SetCheckState(m_recordingRule->m_autoUserJob2); 01208 MythUIText *userjob2Text = NULL; 01209 UIUtilW::Assign(this, userjob2Text, "userjob2text"); 01210 if (userjob2Text) 01211 userjob2Text->SetText(tr("Run '%1'") 01212 .arg(gCoreContext->GetSetting("UserJobDesc2", "User Job 2"))); 01213 01214 // User Job #3 01215 m_userjob3Check->SetCheckState(m_recordingRule->m_autoUserJob3); 01216 MythUIText *userjob3Text = NULL; 01217 UIUtilW::Assign(this, userjob3Text, "userjob3text"); 01218 if (userjob3Text) 01219 userjob3Text->SetText(tr("Run '%1'") 01220 .arg(gCoreContext->GetSetting("UserJobDesc3", "User Job 3"))); 01221 01222 // User Job #4 01223 m_userjob4Check->SetCheckState(m_recordingRule->m_autoUserJob4); 01224 MythUIText *userjob4Text = NULL; 01225 UIUtilW::Assign(this, userjob4Text, "userjob4text"); 01226 if (userjob4Text) 01227 userjob4Text->SetText(tr("Run '%1'") 01228 .arg(gCoreContext->GetSetting("UserJobDesc4", "User Job 4"))); 01229 01230 // Auto Metadata Lookup 01231 if (m_metadataLookupCheck) 01232 m_metadataLookupCheck->SetCheckState(m_recordingRule->m_autoMetadataLookup); 01233 01234 InfoMap progMap; 01235 if (m_recInfo) 01236 m_recInfo->ToMap(progMap); 01237 else 01238 m_recordingRule->ToMap(progMap); 01239 SetTextFromMap(progMap); 01240 } 01241 01242 void PostProcEditor::transcodeEnable(bool enable) 01243 { 01244 m_transcodeprofileList->SetEnabled(enable); 01245 } 01246 01247 void PostProcEditor::Save() 01248 { 01249 // Auto-commflag 01250 m_recordingRule->m_autoCommFlag = m_commflagCheck->GetBooleanCheckState(); 01251 01252 // Auto-transcode 01253 m_recordingRule->m_autoTranscode = m_transcodeCheck->GetBooleanCheckState(); 01254 01255 // Transcode Method 01256 m_recordingRule->m_transcoder = m_transcodeprofileList->GetDataValue().toInt(); 01257 01258 // User Job #1 01259 m_recordingRule->m_autoUserJob1 = m_userjob1Check->GetBooleanCheckState(); 01260 01261 // User Job #2 01262 m_recordingRule->m_autoUserJob2 = m_userjob2Check->GetBooleanCheckState(); 01263 01264 // User Job #3 01265 m_recordingRule->m_autoUserJob3 = m_userjob3Check->GetBooleanCheckState(); 01266 01267 // User Job #4 01268 m_recordingRule->m_autoUserJob4 = m_userjob4Check->GetBooleanCheckState(); 01269 01270 // Auto Metadata Lookup 01271 if (m_metadataLookupCheck) 01272 m_recordingRule->m_autoMetadataLookup = m_metadataLookupCheck->GetBooleanCheckState(); 01273 } 01274 01275 void PostProcEditor::Close() 01276 { 01277 Save(); 01278 MythScreenType::Close(); 01279 } 01280 01282 01288 MetadataOptions::MetadataOptions(MythScreenStack *parent, 01289 RecordingInfo *recInfo, 01290 RecordingRule *rule) 01291 : MythScreenType(parent, "MetadataOptions"), 01292 m_recInfo(NULL), m_recordingRule(rule), m_lookup(NULL), 01293 m_busyPopup(NULL), m_fanart(NULL), m_coverart(NULL), 01294 m_banner(NULL), m_inetrefEdit(NULL), m_seasonSpin(NULL), 01295 m_episodeSpin(NULL), m_queryButton(NULL), m_localFanartButton(NULL), 01296 m_localCoverartButton(NULL), m_localBannerButton(NULL), 01297 m_onlineFanartButton(NULL), m_onlineCoverartButton(NULL), 01298 m_onlineBannerButton(NULL), m_backButton(NULL) 01299 { 01300 m_popupStack = GetMythMainWindow()->GetStack("popup stack"); 01301 01302 m_metadataFactory = new MetadataFactory(this); 01303 m_imageLookup = new MetadataDownload(this); 01304 m_imageDownload = new MetadataImageDownload(this); 01305 01306 m_artworkMap = GetArtwork(m_recordingRule->m_inetref, 01307 m_recordingRule->m_season); 01308 01309 if (recInfo) 01310 m_recInfo = new RecordingInfo(*recInfo); 01311 } 01312 01313 MetadataOptions::~MetadataOptions(void) 01314 { 01315 if (m_imageLookup) 01316 { 01317 m_imageLookup->cancel(); 01318 delete m_imageLookup; 01319 m_imageLookup = NULL; 01320 } 01321 01322 if (m_imageDownload) 01323 { 01324 m_imageDownload->cancel(); 01325 delete m_imageDownload; 01326 m_imageDownload = NULL; 01327 } 01328 } 01329 01330 bool MetadataOptions::Create() 01331 { 01332 if (!LoadWindowFromXML("schedule-ui.xml", "metadataoptions", this)) 01333 return false; 01334 01335 bool err = false; 01336 01337 UIUtilE::Assign(this, m_inetrefEdit, "inetref_edit", &err); 01338 UIUtilE::Assign(this, m_seasonSpin, "season_spinbox", &err); 01339 UIUtilE::Assign(this, m_episodeSpin, "episode_spinbox", &err); 01340 UIUtilE::Assign(this, m_queryButton, "query_button", &err); 01341 UIUtilE::Assign(this, m_localFanartButton, "local_fanart_button", &err); 01342 UIUtilE::Assign(this, m_localCoverartButton, "local_coverart_button", &err); 01343 UIUtilE::Assign(this, m_localBannerButton, "local_banner_button", &err); 01344 UIUtilE::Assign(this, m_onlineFanartButton, "online_fanart_button", &err); 01345 UIUtilE::Assign(this, m_onlineCoverartButton, "online_coverart_button", &err); 01346 UIUtilE::Assign(this, m_onlineBannerButton, "online_banner_button", &err); 01347 UIUtilW::Assign(this, m_fanart, "fanart"); 01348 UIUtilW::Assign(this, m_coverart, "coverart"); 01349 UIUtilW::Assign(this, m_banner, "banner"); 01350 UIUtilW::Assign(this, m_backButton, "back"); 01351 01352 if (err) 01353 { 01354 LOG(VB_GENERAL, LOG_ERR, "MetadataOptions, theme is missing " 01355 "required elements"); 01356 return false; 01357 } 01358 01359 if (m_backButton) 01360 connect(m_backButton, SIGNAL(Clicked()), SLOT(Close())); 01361 connect(m_queryButton, SIGNAL(Clicked()), 01362 SLOT(PerformQuery())); 01363 connect(m_localFanartButton, SIGNAL(Clicked()), 01364 SLOT(SelectLocalFanart())); 01365 connect(m_localCoverartButton, SIGNAL(Clicked()), 01366 SLOT(SelectLocalCoverart())); 01367 connect(m_localBannerButton, SIGNAL(Clicked()), 01368 SLOT(SelectLocalBanner())); 01369 connect(m_onlineFanartButton, SIGNAL(Clicked()), 01370 SLOT(SelectOnlineFanart())); 01371 connect(m_onlineCoverartButton, SIGNAL(Clicked()), 01372 SLOT(SelectOnlineCoverart())); 01373 connect(m_onlineBannerButton, SIGNAL(Clicked()), 01374 SLOT(SelectOnlineBanner())); 01375 01376 connect(m_seasonSpin, SIGNAL(itemSelected(MythUIButtonListItem*)), 01377 SLOT(ValuesChanged())); 01378 01379 // InetRef 01380 m_inetrefEdit->SetText(m_recordingRule->m_inetref); 01381 01382 // Season 01383 m_seasonSpin->SetRange(0,9999,1,1); 01384 m_seasonSpin->SetValue(m_recordingRule->m_season); 01385 01386 // Episode 01387 m_episodeSpin->SetRange(0,9999,1,1); 01388 m_episodeSpin->SetValue(m_recordingRule->m_episode); 01389 01390 if (m_coverart) 01391 { 01392 m_coverart->SetFilename(m_artworkMap.value(kArtworkCoverart).url); 01393 m_coverart->Load(); 01394 } 01395 01396 if (m_fanart) 01397 { 01398 m_fanart->SetFilename(m_artworkMap.value(kArtworkFanart).url); 01399 m_fanart->Load(); 01400 } 01401 01402 if (m_banner) 01403 { 01404 m_banner->SetFilename(m_artworkMap.value(kArtworkBanner).url); 01405 m_banner->Load(); 01406 } 01407 01408 BuildFocusList(); 01409 01410 return true; 01411 } 01412 01413 void MetadataOptions::Load() 01414 { 01415 if (m_recordingRule->m_inetref.isEmpty()) 01416 { 01417 CreateBusyDialog("Trying to automatically find this " 01418 "recording online..."); 01419 01420 m_metadataFactory->Lookup(m_recordingRule, false, false); 01421 } 01422 01423 InfoMap progMap; 01424 if (m_recInfo) 01425 m_recInfo->ToMap(progMap); 01426 else 01427 m_recordingRule->ToMap(progMap); 01428 SetTextFromMap(progMap); 01429 } 01430 01431 void MetadataOptions::CreateBusyDialog(QString title) 01432 { 01433 if (m_busyPopup) 01434 return; 01435 01436 QString message = title; 01437 01438 m_busyPopup = new MythUIBusyDialog(message, m_popupStack, 01439 "metaoptsdialog"); 01440 01441 if (m_busyPopup->Create()) 01442 m_popupStack->AddScreen(m_busyPopup); 01443 } 01444 01445 void MetadataOptions::PerformQuery() 01446 { 01447 m_lookup = new MetadataLookup(); 01448 01449 CreateBusyDialog("Trying to manually find this " 01450 "recording online..."); 01451 01452 m_lookup->SetStep(kLookupSearch); 01453 m_lookup->SetType(kMetadataRecording); 01454 if (m_seasonSpin->GetIntValue() > 0 || 01455 m_episodeSpin->GetIntValue() > 0) 01456 m_lookup->SetSubtype(kProbableTelevision); 01457 else 01458 m_lookup->SetSubtype(kProbableMovie); 01459 m_lookup->SetAutomatic(false); 01460 m_lookup->SetHandleImages(false); 01461 m_lookup->SetHost(gCoreContext->GetMasterHostName()); 01462 m_lookup->SetTitle(m_recordingRule->m_title); 01463 m_lookup->SetSubtitle(m_recordingRule->m_subtitle); 01464 m_lookup->SetInetref(m_inetrefEdit->GetText()); 01465 m_lookup->SetSeason(m_seasonSpin->GetIntValue()); 01466 m_lookup->SetEpisode(m_episodeSpin->GetIntValue()); 01467 01468 m_metadataFactory->Lookup(m_lookup); 01469 } 01470 01471 void MetadataOptions::OnSearchListSelection(MetadataLookup *lookup) 01472 { 01473 if (!lookup) 01474 return; 01475 01476 m_lookup = lookup; 01477 01478 m_metadataFactory->Lookup(lookup); 01479 } 01480 01481 void MetadataOptions::OnImageSearchListSelection(ArtworkInfo info, 01482 VideoArtworkType type) 01483 { 01484 QString msg = tr("Downloading selected artwork..."); 01485 CreateBusyDialog(msg); 01486 01487 m_lookup = new MetadataLookup(); 01488 m_lookup->SetType(kMetadataVideo); 01489 m_lookup->SetHost(gCoreContext->GetMasterHostName()); 01490 m_lookup->SetAutomatic(true); 01491 m_lookup->SetData(qVariantFromValue<VideoArtworkType>(type)); 01492 01493 ArtworkMap downloads; 01494 downloads.insert(type, info); 01495 m_lookup->SetDownloads(downloads); 01496 m_lookup->SetAllowOverwrites(true); 01497 m_lookup->SetTitle(m_recordingRule->m_title); 01498 m_lookup->SetSubtitle(m_recordingRule->m_subtitle); 01499 m_lookup->SetInetref(m_inetrefEdit->GetText()); 01500 m_lookup->SetSeason(m_seasonSpin->GetIntValue()); 01501 m_lookup->SetEpisode(m_episodeSpin->GetIntValue()); 01502 01503 m_imageDownload->addDownloads(m_lookup); 01504 } 01505 01506 void MetadataOptions::SelectLocalFanart() 01507 { 01508 if (!CanSetArtwork()) 01509 return; 01510 01511 QString url = generate_file_url("Fanart", 01512 gCoreContext->GetMasterHostName(), 01513 ""); 01514 FindImagePopup(url,"",*this, "fanart"); 01515 } 01516 01517 void MetadataOptions::SelectLocalCoverart() 01518 { 01519 if (!CanSetArtwork()) 01520 return; 01521 01522 QString url = generate_file_url("Coverart", 01523 gCoreContext->GetMasterHostName(), 01524 ""); 01525 FindImagePopup(url,"",*this, "coverart"); 01526 } 01527 01528 void MetadataOptions::SelectLocalBanner() 01529 { 01530 if (!CanSetArtwork()) 01531 return; 01532 01533 QString url = generate_file_url("Banners", 01534 gCoreContext->GetMasterHostName(), 01535 ""); 01536 FindImagePopup(url,"",*this, "banner"); 01537 } 01538 01539 void MetadataOptions::SelectOnlineFanart() 01540 { 01541 FindNetArt(kArtworkFanart); 01542 } 01543 01544 void MetadataOptions::SelectOnlineCoverart() 01545 { 01546 FindNetArt(kArtworkCoverart); 01547 } 01548 01549 void MetadataOptions::SelectOnlineBanner() 01550 { 01551 FindNetArt(kArtworkBanner); 01552 } 01553 01554 void MetadataOptions::Close() 01555 { 01556 Save(); 01557 MythScreenType::Close(); 01558 } 01559 01560 void MetadataOptions::Save() 01561 { 01562 // Season 01563 if (m_seasonSpin) 01564 m_recordingRule->m_season = m_seasonSpin->GetIntValue(); 01565 01566 // Episode 01567 if (m_episodeSpin) 01568 m_recordingRule->m_episode = m_episodeSpin->GetIntValue(); 01569 01570 // InetRef 01571 if (m_inetrefEdit) 01572 m_recordingRule->m_inetref = m_inetrefEdit->GetText(); 01573 } 01574 01575 void MetadataOptions::QueryComplete(MetadataLookup *lookup) 01576 { 01577 if (!lookup) 01578 return; 01579 01580 m_lookup = lookup; 01581 01582 // InetRef 01583 m_inetrefEdit->SetText(m_lookup->GetInetref()); 01584 01585 // Season 01586 m_seasonSpin->SetValue(m_lookup->GetSeason()); 01587 01588 // Episode 01589 m_episodeSpin->SetValue(m_lookup->GetEpisode()); 01590 01591 MetadataMap metadataMap; 01592 lookup->toMap(metadataMap); 01593 SetTextFromMap(metadataMap); 01594 } 01595 01596 void MetadataOptions::FindImagePopup(const QString &prefix, 01597 const QString &prefixAlt, 01598 QObject &inst, 01599 const QString &returnEvent) 01600 { 01601 QString fp; 01602 01603 if (prefix.startsWith("myth://")) 01604 fp = prefix; 01605 else 01606 fp = prefix.isEmpty() ? prefixAlt : prefix; 01607 01608 MythScreenStack *popupStack = 01609 GetMythMainWindow()->GetStack("popup stack"); 01610 01611 MythUIFileBrowser *fb = new MythUIFileBrowser(popupStack, fp); 01612 fb->SetNameFilter(GetSupportedImageExtensionFilter()); 01613 if (fb->Create()) 01614 { 01615 fb->SetReturnEvent(&inst, returnEvent); 01616 popupStack->AddScreen(fb); 01617 } 01618 else 01619 delete fb; 01620 } 01621 01622 QStringList MetadataOptions::GetSupportedImageExtensionFilter() 01623 { 01624 QStringList ret; 01625 01626 QList<QByteArray> exts = QImageReader::supportedImageFormats(); 01627 for (QList<QByteArray>::iterator p = exts.begin(); p != exts.end(); ++p) 01628 { 01629 ret.append(QString("*.").append(*p)); 01630 } 01631 01632 return ret; 01633 } 01634 01635 bool MetadataOptions::CanSetArtwork() 01636 { 01637 if (m_inetrefEdit->GetText().isEmpty()) 01638 { 01639 ShowOkPopup(tr("You must set a reference number " 01640 "on this rule to set artwork. For items " 01641 "without a metadata source, you can set " 01642 "any unique value.")); 01643 return false; 01644 } 01645 01646 return true; 01647 } 01648 01649 void MetadataOptions::FindNetArt(VideoArtworkType type) 01650 { 01651 if (!CanSetArtwork()) 01652 return; 01653 01654 m_lookup = new MetadataLookup(); 01655 01656 QString msg = tr("Searching for available artwork..."); 01657 CreateBusyDialog(msg); 01658 01659 m_lookup->SetStep(kLookupSearch); 01660 m_lookup->SetType(kMetadataVideo); 01661 m_lookup->SetAutomatic(true); 01662 m_lookup->SetHandleImages(false); 01663 if (m_seasonSpin->GetIntValue() > 0 || 01664 m_episodeSpin->GetIntValue() > 0) 01665 m_lookup->SetSubtype(kProbableTelevision); 01666 else 01667 m_lookup->SetSubtype(kProbableMovie); 01668 m_lookup->SetData(qVariantFromValue<VideoArtworkType>(type)); 01669 m_lookup->SetHost(gCoreContext->GetMasterHostName()); 01670 m_lookup->SetTitle(m_recordingRule->m_title); 01671 m_lookup->SetSubtitle(m_recordingRule->m_subtitle); 01672 m_lookup->SetInetref(m_inetrefEdit->GetText()); 01673 m_lookup->SetSeason(m_seasonSpin->GetIntValue()); 01674 m_lookup->SetEpisode(m_episodeSpin->GetIntValue()); 01675 01676 m_imageLookup->addLookup(m_lookup); 01677 } 01678 01679 void MetadataOptions::OnArtworkSearchDone(MetadataLookup *lookup) 01680 { 01681 if (!lookup) 01682 return; 01683 01684 if (m_busyPopup) 01685 { 01686 m_busyPopup->Close(); 01687 m_busyPopup = NULL; 01688 } 01689 01690 VideoArtworkType type = qVariantValue<VideoArtworkType>(lookup->GetData()); 01691 ArtworkList list = lookup->GetArtwork(type); 01692 01693 if (list.count() == 0) 01694 return; 01695 01696 ImageSearchResultsDialog *resultsdialog = 01697 new ImageSearchResultsDialog(m_popupStack, list, type); 01698 01699 connect(resultsdialog, SIGNAL(haveResult(ArtworkInfo, VideoArtworkType)), 01700 SLOT(OnImageSearchListSelection(ArtworkInfo, VideoArtworkType))); 01701 01702 if (resultsdialog->Create()) 01703 m_popupStack->AddScreen(resultsdialog); 01704 } 01705 01706 void MetadataOptions::HandleDownloadedImages(MetadataLookup *lookup) 01707 { 01708 if (!lookup) 01709 return; 01710 01711 DownloadMap map = lookup->GetDownloads(); 01712 01713 if (!map.size()) 01714 return; 01715 01716 for (DownloadMap::const_iterator i = map.begin(); i != map.end(); ++i) 01717 { 01718 VideoArtworkType type = i.key(); 01719 ArtworkInfo info = i.value(); 01720 01721 if (type == kArtworkCoverart) 01722 m_artworkMap.replace(kArtworkCoverart, info); 01723 else if (type == kArtworkFanart) 01724 m_artworkMap.replace(kArtworkFanart, info); 01725 else if (type == kArtworkBanner) 01726 m_artworkMap.replace(kArtworkBanner, info); 01727 } 01728 01729 SetArtwork(m_inetrefEdit->GetText(), m_seasonSpin->GetIntValue(), 01730 gCoreContext->GetMasterHostName(), m_artworkMap); 01731 01732 ValuesChanged(); 01733 } 01734 01735 void MetadataOptions::ValuesChanged() 01736 { 01737 m_artworkMap = GetArtwork(m_inetrefEdit->GetText(), 01738 m_seasonSpin->GetIntValue()); 01739 01740 if (m_coverart) 01741 { 01742 m_coverart->SetFilename(m_artworkMap.value(kArtworkCoverart).url); 01743 m_coverart->Load(); 01744 } 01745 01746 if (m_fanart) 01747 { 01748 m_fanart->SetFilename(m_artworkMap.value(kArtworkFanart).url); 01749 m_fanart->Load(); 01750 } 01751 01752 if (m_banner) 01753 { 01754 m_banner->SetFilename(m_artworkMap.value(kArtworkBanner).url); 01755 m_banner->Load(); 01756 } 01757 } 01758 01759 void MetadataOptions::customEvent(QEvent *levent) 01760 { 01761 if (levent->type() == MetadataFactoryMultiResult::kEventType) 01762 { 01763 if (m_busyPopup) 01764 { 01765 m_busyPopup->Close(); 01766 m_busyPopup = NULL; 01767 } 01768 01769 MetadataFactoryMultiResult *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent); 01770 01771 if (!mfmr) 01772 return; 01773 01774 MetadataLookupList list = mfmr->results; 01775 01776 if (list.count() > 1) 01777 { 01778 int yearindex = -1; 01779 01780 for (int p = 0; p != list.size(); ++p) 01781 { 01782 if (!m_recordingRule->m_seriesid.isEmpty() && 01783 m_recordingRule->m_seriesid == (list[p])->GetTMSref()) 01784 { 01785 MetadataLookup *lookup = list.takeAt(p); 01786 QueryComplete(lookup); 01787 qDeleteAll(list); 01788 return; 01789 } 01790 else if (m_recInfo && 01791 m_recInfo->GetYearOfInitialRelease() != 0 && 01792 (list[p])->GetYear() != 0 && 01793 m_recInfo->GetYearOfInitialRelease() == (list[p])->GetYear()) 01794 { 01795 if (yearindex > -1) 01796 { 01797 LOG(VB_GENERAL, LOG_INFO, "Multiple results matched on year. No definite " 01798 "match could be found based on year alone."); 01799 yearindex = -2; 01800 } 01801 else if (yearindex == -1) 01802 { 01803 LOG(VB_GENERAL, LOG_INFO, "Matched based on year. "); 01804 yearindex = p; 01805 } 01806 } 01807 } 01808 01809 if (yearindex > -1) 01810 { 01811 MetadataLookup *lookup = list.takeAt(yearindex); 01812 QueryComplete(lookup); 01813 qDeleteAll(list); 01814 return; 01815 } 01816 01817 LOG(VB_GENERAL, LOG_INFO, "Falling through to selection dialog."); 01818 MetadataResultsDialog *resultsdialog = 01819 new MetadataResultsDialog(m_popupStack, list); 01820 01821 connect(resultsdialog, SIGNAL(haveResult(MetadataLookup*)), 01822 SLOT(OnSearchListSelection(MetadataLookup*)), 01823 Qt::QueuedConnection); 01824 01825 if (resultsdialog->Create()) 01826 m_popupStack->AddScreen(resultsdialog); 01827 } 01828 } 01829 else if (levent->type() == MetadataFactorySingleResult::kEventType) 01830 { 01831 if (m_busyPopup) 01832 { 01833 m_busyPopup->Close(); 01834 m_busyPopup = NULL; 01835 } 01836 01837 MetadataFactorySingleResult *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent); 01838 01839 if (!mfsr) 01840 return; 01841 01842 MetadataLookup *lookup = mfsr->result; 01843 01844 if (!lookup) 01845 return; 01846 01847 QueryComplete(lookup); 01848 } 01849 else if (levent->type() == MetadataFactoryNoResult::kEventType) 01850 { 01851 if (m_busyPopup) 01852 { 01853 m_busyPopup->Close(); 01854 m_busyPopup = NULL; 01855 } 01856 01857 MetadataFactoryNoResult *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent); 01858 01859 if (!mfnr) 01860 return; 01861 01862 MetadataLookup *lookup = mfnr->result; 01863 01864 delete lookup; 01865 lookup = NULL; 01866 01867 QString title = "No match found for this recording. You can " 01868 "try entering a TVDB/TMDB number, season, and " 01869 "episode manually."; 01870 01871 MythConfirmationDialog *okPopup = 01872 new MythConfirmationDialog(m_popupStack, title, false); 01873 01874 if (okPopup->Create()) 01875 m_popupStack->AddScreen(okPopup); 01876 } 01877 else if (levent->type() == MetadataLookupEvent::kEventType) 01878 { 01879 if (m_busyPopup) 01880 { 01881 m_busyPopup->Close(); 01882 m_busyPopup = NULL; 01883 } 01884 01885 MetadataLookupEvent *lue = (MetadataLookupEvent *)levent; 01886 01887 MetadataLookupList lul = lue->lookupList; 01888 01889 if (lul.isEmpty()) 01890 return; 01891 01892 if (lul.count() >= 1) 01893 { 01894 OnArtworkSearchDone(lul.takeFirst()); 01895 } 01896 } 01897 else if (levent->type() == MetadataLookupFailure::kEventType) 01898 { 01899 if (m_busyPopup) 01900 { 01901 m_busyPopup->Close(); 01902 m_busyPopup = NULL; 01903 } 01904 01905 MetadataLookupFailure *luf = (MetadataLookupFailure *)levent; 01906 01907 MetadataLookupList lul = luf->lookupList; 01908 01909 if (lul.size()) 01910 { 01911 MetadataLookup *lookup = lul.takeFirst(); 01912 01913 QString title = "This number, season, and episode combination " 01914 "does not appear to be valid (or the site may " 01915 "be down). Check your information and try again."; 01916 01917 MythConfirmationDialog *okPopup = 01918 new MythConfirmationDialog(m_popupStack, title, false); 01919 01920 if (okPopup->Create()) 01921 m_popupStack->AddScreen(okPopup); 01922 01923 delete lookup; 01924 lookup = NULL; 01925 } 01926 } 01927 else if (levent->type() == ImageDLEvent::kEventType) 01928 { 01929 if (m_busyPopup) 01930 { 01931 m_busyPopup->Close(); 01932 m_busyPopup = NULL; 01933 } 01934 01935 ImageDLEvent *ide = (ImageDLEvent *)levent; 01936 01937 MetadataLookup *lookup = ide->item; 01938 01939 if (!lookup) 01940 return; 01941 01942 HandleDownloadedImages(lookup); 01943 } 01944 else if (levent->type() == ImageDLFailureEvent::kEventType) 01945 { 01946 if (m_busyPopup) 01947 { 01948 m_busyPopup->Close(); 01949 m_busyPopup = NULL; 01950 } 01951 01952 ImageDLFailureEvent *ide = (ImageDLFailureEvent *)levent; 01953 01954 MetadataLookup *lookup = ide->item; 01955 01956 if (!lookup) 01957 return; 01958 01959 delete lookup; 01960 lookup = NULL; 01961 } 01962 else if (levent->type() == DialogCompletionEvent::kEventType) 01963 { 01964 DialogCompletionEvent *dce = (DialogCompletionEvent*)(levent); 01965 01966 const QString resultid = dce->GetId(); 01967 ArtworkInfo info; 01968 info.url = dce->GetResultText(); 01969 01970 if (resultid == "coverart") 01971 { 01972 m_artworkMap.replace(kArtworkCoverart, info); 01973 } 01974 else if (resultid == "fanart") 01975 { 01976 m_artworkMap.replace(kArtworkFanart, info); 01977 } 01978 else if (resultid == "banner") 01979 { 01980 m_artworkMap.replace(kArtworkBanner, info); 01981 } 01982 01983 SetArtwork(m_inetrefEdit->GetText(), m_seasonSpin->GetIntValue(), 01984 gCoreContext->GetMasterHostName(), m_artworkMap); 01985 01986 ValuesChanged(); 01987 } 01988 01989 } 01990
1.7.6.1