00001
00002
00003 #include <cstdlib>
00004 #include <stdlib.h>
00005 #include <unistd.h>
00006
00007
00008 #include <QDir>
00009 #include <QKeyEvent>
00010 #include <QTimer>
00011 #include <QApplication>
00012
00013
00014 #include <mythcontext.h>
00015 #include <mythdb.h>
00016 #include <mthread.h>
00017 #include <programinfo.h>
00018 #include <remoteutil.h>
00019 #include <mythtimer.h>
00020 #include <mythuitext.h>
00021 #include <mythuibutton.h>
00022 #include <mythuiimage.h>
00023 #include <mythuibuttonlist.h>
00024 #include <mythmainwindow.h>
00025 #include <mythprogressdialog.h>
00026 #include <mythdialogbox.h>
00027 #include <mythlogging.h>
00028 #include <mythmiscutil.h>
00029 #include <netutils.h>
00030
00031
00032 #include "recordingselector.h"
00033 #include "archiveutil.h"
00034
00035 class GetRecordingListThread : public MThread
00036 {
00037 public:
00038 GetRecordingListThread(RecordingSelector *parent) :
00039 MThread("GetRecordingList"), m_parent(parent)
00040 {
00041 start();
00042 }
00043
00044 virtual void run(void)
00045 {
00046 RunProlog();
00047 m_parent->getRecordingList();
00048 RunEpilog();
00049 }
00050
00051 RecordingSelector *m_parent;
00052 };
00053
00054 RecordingSelector::RecordingSelector(
00055 MythScreenStack *parent, QList<ArchiveItem *> *archiveList) :
00056 MythScreenType(parent, "RecordingSelector"),
00057 m_archiveList(archiveList),
00058 m_recordingList(NULL),
00059 m_recordingButtonList(NULL),
00060 m_okButton(NULL),
00061 m_cancelButton(NULL),
00062 m_categorySelector(NULL),
00063 m_titleText(NULL),
00064 m_datetimeText(NULL),
00065 m_filesizeText(NULL),
00066 m_descriptionText(NULL),
00067 m_previewImage(NULL),
00068 m_cutlistImage(NULL)
00069 {
00070 }
00071
00072 RecordingSelector::~RecordingSelector(void)
00073 {
00074 if (m_recordingList)
00075 delete m_recordingList;
00076
00077 while (!m_selectedList.isEmpty())
00078 delete m_selectedList.takeFirst();
00079 }
00080
00081 bool RecordingSelector::Create(void)
00082 {
00083 bool foundtheme = false;
00084
00085
00086 foundtheme = LoadWindowFromXML("mytharchive-ui.xml", "recording_selector", this);
00087
00088 if (!foundtheme)
00089 return false;
00090
00091 bool err = false;
00092 UIUtilE::Assign(this, m_okButton, "ok_button", &err);
00093 UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
00094 UIUtilE::Assign(this, m_categorySelector, "category_selector", &err);
00095 UIUtilE::Assign(this, m_recordingButtonList, "recordinglist", &err);
00096
00097 UIUtilW::Assign(this, m_titleText, "progtitle", &err);
00098 UIUtilW::Assign(this, m_datetimeText, "progdatetime", &err);
00099 UIUtilW::Assign(this, m_descriptionText, "progdescription", &err);
00100 UIUtilW::Assign(this, m_filesizeText, "filesize", &err);
00101 UIUtilW::Assign(this, m_previewImage, "preview_image", &err);
00102 UIUtilW::Assign(this, m_cutlistImage, "cutlist_image", &err);
00103
00104 if (err)
00105 {
00106 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'recording_selector'");
00107 return false;
00108 }
00109
00110 connect(m_okButton, SIGNAL(Clicked()), this, SLOT(OKPressed()));
00111 connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(cancelPressed()));
00112
00113 new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
00114 connect(m_categorySelector, SIGNAL(itemSelected(MythUIButtonListItem *)),
00115 this, SLOT(setCategory(MythUIButtonListItem *)));
00116
00117 connect(m_recordingButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00118 this, SLOT(titleChanged(MythUIButtonListItem *)));
00119 connect(m_recordingButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)),
00120 this, SLOT(toggleSelected(MythUIButtonListItem *)));
00121
00122 if (m_cutlistImage)
00123 m_cutlistImage->Hide();
00124
00125 BuildFocusList();
00126
00127 SetFocusWidget(m_recordingButtonList);
00128
00129 return true;
00130 }
00131
00132 void RecordingSelector::Init(void)
00133 {
00134 QString message = tr("Retrieving Recording List.\nPlease Wait...");
00135
00136 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00137
00138 MythUIBusyDialog *busyPopup = new
00139 MythUIBusyDialog(message, popupStack, "recordingselectorbusydialog");
00140
00141 if (busyPopup->Create())
00142 popupStack->AddScreen(busyPopup, false);
00143 else
00144 {
00145 delete busyPopup;
00146 busyPopup = NULL;
00147 }
00148
00149 GetRecordingListThread *thread = new GetRecordingListThread(this);
00150 while (thread->isRunning())
00151 {
00152 qApp->processEvents();
00153 usleep(2000);
00154 }
00155
00156 if (!m_recordingList || m_recordingList->empty())
00157 {
00158 ShowOkPopup(tr("Either you don't have any recordings or "
00159 "no recordings are available locally!"));
00160 if (busyPopup)
00161 busyPopup->Close();
00162
00163 Close();
00164 return;
00165 }
00166
00167 updateCategorySelector();
00168 updateSelectedList();
00169 updateRecordingList();
00170
00171 if (busyPopup)
00172 busyPopup->Close();
00173 }
00174
00175 bool RecordingSelector::keyPressEvent(QKeyEvent *event)
00176 {
00177 if (GetFocusWidget()->keyPressEvent(event))
00178 return true;
00179
00180 bool handled = false;
00181 QStringList actions;
00182 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
00183
00184 for (int i = 0; i < actions.size() && !handled; i++)
00185 {
00186 QString action = actions[i];
00187 handled = true;
00188
00189 if (action == "MENU")
00190 {
00191 showMenu();
00192 }
00193 else
00194 handled = false;
00195 }
00196
00197 if (!handled && MythScreenType::keyPressEvent(event))
00198 handled = true;
00199
00200 return handled;
00201 }
00202
00203 void RecordingSelector::showMenu()
00204 {
00205 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00206
00207 MythDialogBox *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
00208
00209 if (menuPopup->Create())
00210 popupStack->AddScreen(menuPopup);
00211
00212 menuPopup->SetReturnEvent(this, "action");
00213
00214 menuPopup->AddButton(tr("Clear All"), SLOT(clearAll()));
00215 menuPopup->AddButton(tr("Select All"), SLOT(selectAll()));
00216 }
00217
00218 void RecordingSelector::selectAll()
00219 {
00220 while (!m_selectedList.isEmpty())
00221 m_selectedList.takeFirst();
00222 m_selectedList.clear();
00223
00224 ProgramInfo *p;
00225 vector<ProgramInfo *>::iterator i = m_recordingList->begin();
00226 for ( ; i != m_recordingList->end(); ++i)
00227 {
00228 p = *i;
00229 m_selectedList.append(p);
00230 }
00231
00232 updateRecordingList();
00233 }
00234
00235 void RecordingSelector::clearAll()
00236 {
00237 while (!m_selectedList.isEmpty())
00238 m_selectedList.takeFirst();
00239 m_selectedList.clear();
00240
00241 updateRecordingList();
00242 }
00243
00244 void RecordingSelector::toggleSelected(MythUIButtonListItem *item)
00245 {
00246 if (item->state() == MythUIButtonListItem:: FullChecked)
00247 {
00248 int index = m_selectedList.indexOf(
00249 qVariantValue<ProgramInfo *>(item->GetData()));
00250 if (index != -1)
00251 m_selectedList.takeAt(index);
00252 item->setChecked(MythUIButtonListItem:: NotChecked);
00253 }
00254 else
00255 {
00256 int index = m_selectedList.indexOf(
00257 qVariantValue<ProgramInfo *>(item->GetData()));
00258 if (index == -1)
00259 m_selectedList.append(qVariantValue<ProgramInfo *>(item->GetData()));
00260
00261 item->setChecked(MythUIButtonListItem::FullChecked);
00262 }
00263 }
00264
00265 void RecordingSelector::titleChanged(MythUIButtonListItem *item)
00266 {
00267 ProgramInfo *p;
00268
00269 p = qVariantValue<ProgramInfo *>(item->GetData());
00270
00271 if (!p)
00272 return;
00273
00274 if (m_titleText)
00275 m_titleText->SetText(p->GetTitle());
00276
00277 if (m_datetimeText)
00278 m_datetimeText->SetText(p->GetScheduledStartTime()
00279 .toString("dd MMM yy (hh:mm)"));
00280
00281 if (m_descriptionText)
00282 {
00283 m_descriptionText->SetText(
00284 ((!p->GetSubtitle().isEmpty()) ? p->GetSubtitle() + "\n" : "") +
00285 p->GetDescription());
00286 }
00287
00288 if (m_filesizeText)
00289 {
00290 m_filesizeText->SetText(formatSize(p->GetFilesize() / 1024));
00291 }
00292
00293 if (m_cutlistImage)
00294 {
00295 if (p->HasCutlist())
00296 m_cutlistImage->Show();
00297 else
00298 m_cutlistImage->Hide();
00299 }
00300
00301 if (m_previewImage)
00302 {
00303
00304 if (QFile::exists(p->GetPathname() + ".png"))
00305 {
00306 m_previewImage->SetFilename(p->GetPathname() + ".png");
00307 m_previewImage->Load();
00308 }
00309 else
00310 {
00311 m_previewImage->SetFilename("blank.png");
00312 m_previewImage->Load();
00313 }
00314 }
00315 }
00316
00317 void RecordingSelector::OKPressed()
00318 {
00319
00320 ProgramInfo *p;
00321 ArchiveItem *a;
00322
00323
00324 QList<ArchiveItem *> tempAList;
00325 for (int x = 0; x < m_archiveList->size(); x++)
00326 {
00327 a = m_archiveList->at(x);
00328 bool found = false;
00329
00330 for (int y = 0; y < m_selectedList.size(); y++)
00331 {
00332 p = m_selectedList.at(y);
00333 if (a->type != "Recording" || a->filename == p->GetPlaybackURL(false, true))
00334 {
00335 found = true;
00336 break;
00337 }
00338 }
00339
00340 if (!found)
00341 tempAList.append(a);
00342 }
00343
00344 for (int x = 0; x < tempAList.size(); x++)
00345 m_archiveList->removeAll(tempAList.at(x));
00346
00347
00348 QList<ProgramInfo *> tempSList;
00349 for (int x = 0; x < m_selectedList.size(); x++)
00350 {
00351 p = m_selectedList.at(x);
00352
00353 for (int y = 0; y < m_archiveList->size(); y++)
00354 {
00355 a = m_archiveList->at(y);
00356 if (a->filename == p->GetPlaybackURL(false, true))
00357 {
00358 tempSList.append(p);
00359 break;
00360 }
00361 }
00362 }
00363
00364 for (int x = 0; x < tempSList.size(); x++)
00365 m_selectedList.removeAll(tempSList.at(x));
00366
00367
00368 for (int x = 0; x < m_selectedList.size(); x++)
00369 {
00370 p = m_selectedList.at(x);
00371 a = new ArchiveItem;
00372 a->type = "Recording";
00373 a->title = p->GetTitle();
00374 a->subtitle = p->GetSubtitle();
00375 a->description = p->GetDescription();
00376 a->startDate = p->GetScheduledStartTime().toString("dd MMM yy");
00377 a->startTime = p->GetScheduledStartTime().toString("(hh:mm)");
00378 a->size = p->GetFilesize();
00379 a->filename = p->GetPlaybackURL(false, true);
00380 a->hasCutlist = p->HasCutlist();
00381 a->useCutlist = false;
00382 a->duration = 0;
00383 a->cutDuration = 0;
00384 a->videoWidth = 0;
00385 a->videoHeight = 0;
00386 a->fileCodec = "";
00387 a->videoCodec = "";
00388 a->encoderProfile = NULL;
00389 a->editedDetails = false;
00390 m_archiveList->append(a);
00391 }
00392
00393 emit haveResult(true);
00394 Close();
00395 }
00396
00397 void RecordingSelector::cancelPressed()
00398 {
00399 emit haveResult(false);
00400 Close();
00401 }
00402
00403 void RecordingSelector::updateRecordingList(void)
00404 {
00405 if (!m_recordingList || m_recordingList->empty())
00406 return;
00407
00408 m_recordingButtonList->Reset();
00409
00410 if (m_categorySelector)
00411 {
00412 ProgramInfo *p;
00413 vector<ProgramInfo *>::iterator i = m_recordingList->begin();
00414 for ( ; i != m_recordingList->end(); ++i)
00415 {
00416 p = *i;
00417
00418 if (p->GetTitle() == m_categorySelector->GetValue() ||
00419 m_categorySelector->GetValue() == tr("All Recordings"))
00420 {
00421 MythUIButtonListItem* item = new MythUIButtonListItem(
00422 m_recordingButtonList,
00423 p->GetTitle() + " ~ " +
00424 p->GetScheduledStartTime().toString("dd MMM yy (hh:mm)"));
00425 item->setCheckable(true);
00426 if (m_selectedList.indexOf((ProgramInfo *) p) != -1)
00427 {
00428 item->setChecked(MythUIButtonListItem::FullChecked);
00429 }
00430 else
00431 {
00432 item->setChecked(MythUIButtonListItem::NotChecked);
00433 }
00434
00435 QString title = p->GetTitle();
00436 QString subtitle = p->GetSubtitle();
00437
00438 QDateTime recstartts = p->GetScheduledStartTime();
00439 QDateTime recendts = p->GetScheduledEndTime();
00440
00441 QString timedate = QString("%1 - %2")
00442 .arg(MythDateTimeToString
00443 (recstartts, kDateTimeFull))
00444 .arg(MythDateTimeToString(recendts, kTime));
00445
00446 uint season = p->GetSeason();
00447 uint episode = p->GetEpisode();
00448 QString seasone, seasonx;
00449
00450 if (season && episode)
00451 {
00452 seasone = QString("s%1e%2")
00453 .arg(GetDisplaySeasonEpisode(season, 2))
00454 .arg(GetDisplaySeasonEpisode(episode, 2));
00455 seasonx = QString("%1x%2")
00456 .arg(GetDisplaySeasonEpisode(season, 1))
00457 .arg(GetDisplaySeasonEpisode(episode, 2));
00458 }
00459
00460 item->SetText(title, "title");
00461 item->SetText(subtitle, "subtitle");
00462 if (subtitle.isEmpty())
00463 item->SetText(title, "titlesubtitle");
00464 else
00465 item->SetText(title + " - \"" + subtitle + '"',
00466 "titlesubtitle");
00467
00468 item->SetText(timedate, "timedate");
00469 item->SetText(p->GetDescription(), "description");
00470 item->SetText(formatSize(p->GetFilesize() / 1024),
00471 "filesize_str");
00472
00473 item->SetText(QString::number(season), "season");
00474 item->SetText(QString::number(episode), "episode");
00475 item->SetText(seasonx, "00x00");
00476 item->SetText(seasone, "s00e00");
00477
00478 item->DisplayState(p->HasCutlist() ? "yes" : "no", "cutlist");
00479
00480 item->SetData(qVariantFromValue(p));
00481 }
00482 qApp->processEvents();
00483 }
00484 }
00485
00486 m_recordingButtonList->SetItemCurrent(m_recordingButtonList->GetItemFirst());
00487 titleChanged(m_recordingButtonList->GetItemCurrent());
00488 }
00489
00490 void RecordingSelector::getRecordingList(void)
00491 {
00492 ProgramInfo *p;
00493 m_recordingList = RemoteGetRecordedList(-1);
00494 m_categories.clear();
00495
00496 if (m_recordingList && !m_recordingList->empty())
00497 {
00498 vector<ProgramInfo *>::iterator i = m_recordingList->begin();
00499 for ( ; i != m_recordingList->end(); ++i)
00500 {
00501 p = *i;
00502
00503 if (p->GetRecordingGroup() == "LiveTV" ||
00504 p->GetRecordingGroup() == "Deleted")
00505 {
00506 i = m_recordingList->erase(i);
00507 --i;
00508 continue;
00509 }
00510
00511 if (m_categories.indexOf(p->GetTitle()) == -1)
00512 m_categories.append(p->GetTitle());
00513 }
00514 }
00515 }
00516
00517 void RecordingSelector::updateCategorySelector(void)
00518 {
00519
00520 m_categories.sort();
00521
00522 if (m_categorySelector)
00523 {
00524 new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
00525 m_categorySelector->SetItemCurrent(0);
00526
00527 for (int x = 0; x < m_categories.count(); x++)
00528 {
00529 new MythUIButtonListItem(m_categorySelector, m_categories[x]);
00530 }
00531 }
00532 }
00533
00534 void RecordingSelector::setCategory(MythUIButtonListItem *item)
00535 {
00536 (void)item;
00537 updateRecordingList();
00538 }
00539
00540 void RecordingSelector::updateSelectedList()
00541 {
00542 if (!m_recordingList)
00543 return;
00544
00545 m_selectedList.clear();
00546
00547 ProgramInfo *p;
00548 ArchiveItem *a;
00549 for (int x = 0; x < m_archiveList->size(); x++)
00550 {
00551 a = m_archiveList->at(x);
00552 for (uint y = 0; y < m_recordingList->size(); y++)
00553 {
00554 p = m_recordingList->at(y);
00555 if (p->GetPlaybackURL(false, true) == a->filename)
00556 {
00557 if (m_selectedList.indexOf(p) == -1)
00558 m_selectedList.append(p);
00559 break;
00560 }
00561
00562 qApp->processEvents();
00563 }
00564 }
00565 }