MythTV  master
streamview.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstdlib>
3 
4 // qt
5 #include <QKeyEvent>
6 #include <QRegExp>
7 #include <QThread>
8 #include <QDomDocument>
9 
10 // myth
11 #include <mythcontext.h>
12 #include <mythdbcon.h>
13 #include <mythmainwindow.h>
14 #include <mythuibuttonlist.h>
15 #include <mythuibutton.h>
16 #include <mythuitext.h>
17 #include <mythuiprogressbar.h>
18 #include <mythuiutils.h>
19 #include <mythdialogbox.h>
20 #include <mythuihelper.h>
21 #include <mythdownloadmanager.h>
22 #include <mythdirs.h>
23 #include <musicutils.h>
24 #include <mythcoreutil.h>
25 
26 // mythmusic
27 #include "musicdata.h"
28 #include "musiccommon.h"
29 #include "streamview.h"
30 #include "musicplayer.h"
31 
32 using namespace std;
33 
34 
36  : MusicCommon(parent, parentScreen, "streamview")
37 {
39 }
40 
42 {
43  // Load the theme for this screen
44  bool err = LoadWindowFromXML("stream-ui.xml", "streamview", this);
45 
46  if (!err)
47  return false;
48 
49  // find common widgets available on any view
50  err = CreateCommon();
51 
52  // find widgets specific to this view
53  UIUtilE::Assign(this, m_streamList, "streamlist", &err);
54  UIUtilW::Assign(this, m_bufferStatus, "bufferstatus", &err);
55  UIUtilW::Assign(this, m_bufferProgress, "bufferprogress", &err);
56  UIUtilW::Assign(this, m_noStreams, "nostreams", &err);
57 
58  if (err)
59  {
60  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'streamview'");
61  return false;
62  }
63 
64  connect(m_streamList, SIGNAL(itemClicked(MythUIButtonListItem*)),
66  connect(m_streamList, SIGNAL(itemVisible(MythUIButtonListItem*)),
68 
70 
73 
75 
76  return true;
77 }
78 
80 {
81  auto *menu = new MythMenu(tr("Stream Actions"), this, "mainmenu");
82  menu->AddItem(tr("Add Stream"));
83 
85  {
86  menu->AddItem(tr("Edit Stream"));
87  menu->AddItem(tr("Remove Stream"));
88  }
89 
90  menu->AddItem(MusicCommon::tr("Fullscreen Visualizer"), QVariant::fromValue((int)MV_VISUALIZER));
91  menu->AddItem(MusicCommon::tr("Lyrics"), QVariant::fromValue((int)MV_LYRICS));
92 
93  menu->AddItem(tr("More Options"), nullptr, createSubMenu());
94 
95  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
96 
97  auto *menuPopup = new MythDialogBox(menu, popupStack, "actionmenu");
98 
99  if (menuPopup->Create())
100  popupStack->AddScreen(menuPopup);
101  else
102  delete menu;
103 }
104 
105 void StreamView::customEvent(QEvent *event)
106 {
107  bool handled = true;
108 
109  if (event->type() == MusicPlayerEvent::PlayedTracksChangedEvent)
110  {
111  if (gPlayer->getPlayedTracksList().count())
113 
114  // add the new track to the list
116  {
117  MusicMetadata *mdata = gPlayer->getPlayedTracksList().last();
118 
119  auto *item = new MythUIButtonListItem(m_playedTracksList, "",
120  QVariant::fromValue(mdata), 0);
121 
122  InfoMap metadataMap;
123  mdata->toMap(metadataMap);
124  item->SetTextFromMap(metadataMap);
125  item->SetFontState("normal");
126  item->DisplayState("default", "playstate");
127  item->SetImage(mdata->getAlbumArtFile());
128 
130  }
131  }
132  else if (event->type() == MusicPlayerEvent::TrackChangeEvent)
133  {
134  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
135 
136  if (!mpe)
137  return;
138 
139  if (m_streamList)
140  {
141  MythUIButtonListItem *item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
142  if (item)
143  {
144  item->SetFontState("normal");
145  item->DisplayState("default", "playstate");
146  }
147 
149  {
152  }
153 
154  item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
155  if (item)
156  {
157  if (gPlayer->isPlaying())
158  {
159  item->SetFontState("running");
160  item->DisplayState("playing", "playstate");
161  }
162  else if (gPlayer->isPaused())
163  {
164  item->SetFontState("idle");
165  item->DisplayState("paused", "playstate");
166  }
167  else
168  {
169  item->SetFontState("normal");
170  item->DisplayState("stopped", "playstate");
171  }
172  }
173  }
174 
176  }
177  else if (event->type() == OutputEvent::Playing)
178  {
179  if (gPlayer->isPlaying())
180  {
181  if (m_streamList)
182  {
183  MythUIButtonListItem *item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
184  if (item)
185  {
186  item->SetFontState("running");
187  item->DisplayState("playing", "playstate");
188  }
189  }
190  }
191 
192  // pass it on to the default handler in MusicCommon
193  handled = false;
194  }
195  else if (event->type() == OutputEvent::Stopped)
196  {
197  if (m_streamList)
198  {
199  MythUIButtonListItem *item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
200  if (item)
201  {
202  item->SetFontState("normal");
203  item->DisplayState("stopped", "playstate");
204  }
205  }
206 
207  // pass it on to the default handler in MusicCommon
208  handled = false;
209  }
210  else if (event->type() == OutputEvent::Buffering)
211  {
212  }
213  else if (event->type() == MythEvent::MythEventMessage)
214  {
215  auto *me = dynamic_cast<MythEvent *>(event);
216  if (me == nullptr)
217  return;
218  QStringList tokens = me->Message().split(" ", QString::SkipEmptyParts);
219 
220  if (tokens.isEmpty())
221  return;
222 
223  if (tokens[0] == "DOWNLOAD_FILE")
224  {
225  QStringList args = me->ExtraDataList();
226 
227  if (tokens[1] == "UPDATE")
228  {
229  }
230  else if (tokens[1] == "FINISHED")
231  {
232  QString url = args[0];
233  int fileSize = args[2].toInt();
234  int errorCode = args[4].toInt();
235  QString filename = args[1];
236 
237  if ((errorCode != 0) || (fileSize == 0))
238  LOG(VB_GENERAL, LOG_ERR, QString("StreamView: failed to download radio icon from '%1'").arg(url));
239  else
240  {
241  for (int x = 0; x < m_streamList->GetCount(); x++)
242  {
244  auto *mdata = item->GetData().value<MusicMetadata *>();
245  if (mdata && mdata->LogoUrl() == url)
246  item->SetImage(filename);
247  }
248  }
249  }
250  }
251  }
252  else if (event->type() == DecoderHandlerEvent::OperationStart)
253  {
254  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
255  if (!dhe)
256  return;
257  if (dhe->getMessage() && m_bufferStatus)
258  {
259  m_bufferStatus->SetText(*dhe->getMessage());
260  }
261  }
262  else if (event->type() == DecoderHandlerEvent::BufferStatus)
263  {
264  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
265  if (!dhe)
266  return;
267 
268  int available = 0;
269  int maxSize = 0;
270  dhe->getBufferStatus(&available, &maxSize);
271 
272  if (m_bufferStatus)
273  {
274  QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
275  m_bufferStatus->SetText(status);
276  }
277 
278  if (m_bufferProgress)
279  {
280  m_bufferProgress->SetTotal(maxSize);
281  m_bufferProgress->SetUsed(available);
282  }
283  }
284  else if (event->type() == DecoderHandlerEvent::OperationStop)
285  {
286  if (m_bufferStatus)
288  }
289  else if (event->type() == DialogCompletionEvent::kEventType)
290  {
291  auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
292 
293  // make sure the user didn't ESCAPE out of the menu
294  if ((dce == nullptr) || (dce->GetResult() < 0))
295  return;
296 
297  QString resultid = dce->GetId();
298  QString resulttext = dce->GetResultText();
299 
300  if (resultid == "mainmenu")
301  {
302  if (resulttext == tr("Add Stream"))
303  {
305  MythScreenType *screen = new EditStreamMetadata(mainStack, this, nullptr);
306 
307  if (screen->Create())
308  mainStack->AddScreen(screen);
309  else
310  delete screen;
311  }
312  else if (resulttext == tr("Remove Stream"))
313  {
314  removeStream();
315  }
316  else if (resulttext == tr("Edit Stream"))
317  {
318  editStream();
319  }
320  else
321  handled = false;
322  }
323  else
324  handled = false;
325  }
326  else
327  handled = false;
328 
329 
330  if (!handled)
332 }
333 
334 bool StreamView::keyPressEvent(QKeyEvent *event)
335 {
336  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
337  return true;
338 
339  QStringList actions;
340  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
341 
342  for (int i = 0; i < actions.size() && !handled; i++)
343  {
344  QString action = actions[i];
345  handled = true;
346 
347  if (action == "EDIT")
348  {
349  editStream();
350  }
351  else if (action == "DELETE")
352  {
353  removeStream();
354  }
355  else if (action == "TOGGLELAST")
356  {
358  {
359  m_streamList->SetValueByData(QVariant::fromValue(m_lastStream));
360 
362  if (item)
363  streamItemClicked(item);
364  }
365  }
366  else
367  handled = false;
368  }
369 
370  if (!handled && MusicCommon::keyPressEvent(event))
371  handled = true;
372 
373  return handled;
374 }
375 
377 {
379  if (item)
380  {
381  auto *mdata = item->GetData().value<MusicMetadata *>();
383  MythScreenType *screen = new EditStreamMetadata(mainStack, this, mdata);
384 
385  if (screen->Create())
386  mainStack->AddScreen(screen);
387  else
388  delete screen;
389  }
390 }
391 
393 {
395  if (item)
396  {
397  auto *mdata = item->GetData().value<MusicMetadata *>();
398 
399  if (mdata)
400  {
401  ShowOkPopup(tr("Are you sure you want to delete this Stream?\n"
402  "Broadcaster: %1 - Channel: %2")
403  .arg(mdata->Broadcaster()).arg(mdata->Channel()),
404  this, SLOT(doRemoveStream(bool)), true);
405  }
406  }
407 }
408 
410 {
411  if (!ok)
412  return;
413 
415  if (item)
416  {
417  auto *mdata = item->GetData().value<MusicMetadata *>();
418 
419  if (mdata)
420  deleteStream(mdata);
421  }
422 }
423 
425 {
426  if (!gPlayer->getCurrentPlaylist())
427  return;
428 
429  m_streamList->Reset();
430 
431  bool foundActiveStream = false;
432 
433  for (int x = 0; x < gPlayer->getCurrentPlaylist()->getTrackCount(); x++)
434  {
436  auto *item = new MythUIButtonListItem(m_streamList, "",
437  QVariant::fromValue(mdata));
438  InfoMap metadataMap;
439  if (mdata)
440  mdata->toMap(metadataMap);
441  item->SetTextFromMap(metadataMap);
442  item->SetText("", "imageloaded");
443  item->SetFontState("normal");
444  item->DisplayState("default", "playstate");
445 
446  // if this is the current radio stream update its play state to match the player
447  if (gPlayer->getCurrentMetadata() && mdata &&
448  mdata->ID() == gPlayer->getCurrentMetadata()->ID())
449  {
450  if (gPlayer->isPlaying())
451  {
452  item->SetFontState("running");
453  item->DisplayState("playing", "playstate");
454  }
455  else if (gPlayer->isPaused())
456  {
457  item->SetFontState("idle");
458  item->DisplayState("paused", "playstate");
459  }
460  else
461  {
462  item->SetFontState("normal");
463  item->DisplayState("stopped", "playstate");
464  }
465 
467 
469 
470  foundActiveStream = true;
471  }
472  }
473 
474  if (m_streamList->GetCount() > 0 && !foundActiveStream)
475  {
477  gPlayer->stop(true);
478  }
479 
480  if (m_noStreams)
482 
483  if (m_streamList->GetCount() == 0)
484  LOG(VB_GENERAL, LOG_ERR, "StreamView hasn't found any streams!");
485 }
486 
488 {
489  if (!item)
490  return;
491 
493 }
494 
496 {
497  if (!item)
498  return;
499 
500  if (!item->GetText("imageloaded").isEmpty())
501  return;
502 
503  auto *mdata = item->GetData().value<MusicMetadata *>();
504  if (mdata)
505  {
506  if (!mdata->LogoUrl().isEmpty())
507  item->SetImage(mdata->getAlbumArtFile());
508  else
509  item->SetImage("");
510  }
511 
512  item->SetText(" ", "imageloaded");
513 }
514 
516 {
517  // sanity check this is a radio stream
518  int repo = ID_TO_REPO(mdata->ID());
519  if (repo != RT_Radio)
520  {
521  LOG(VB_GENERAL, LOG_ERR, "StreamView asked to add a stream but it isn't a radio stream!");
522  return;
523  }
524 
525  QString url = mdata->Url();
526 
528 
530 
532 
533  // find the new stream and make it the active item
534  for (int x = 0; x < m_streamList->GetCount(); x++)
535  {
537  auto *itemsdata = item->GetData().value<MusicMetadata *>();
538  if (itemsdata)
539  {
540  if (url == itemsdata->Url())
541  {
543  break;
544  }
545  }
546  }
547 }
548 
550 {
551  // sanity check this is a radio stream
552  int repo = ID_TO_REPO(mdata->ID());
553  if (repo != RT_Radio)
554  {
555  LOG(VB_GENERAL, LOG_ERR, "StreamView asked to update a stream but it isn't a radio stream!");
556  return;
557  }
558 
559  MusicMetadata::IdType id = mdata->ID();
560 
562 
564 
565  // update mdata to point to the new item
566  mdata = gMusicData->m_all_streams->getMetadata(id);
567 
568  if (!mdata)
569  return;
570 
571  // force the icon to reload incase it changed
572  QFile::remove(mdata->getAlbumArtFile());
573  mdata->reloadAlbumArtImages();
574 
576 
577  // if we just edited the currently playing stream update the current metadata to match
578  MusicMetadata *currentMetadata = gPlayer->getCurrentMetadata();
579  if (id == currentMetadata->ID())
580  {
581  currentMetadata->setBroadcaster(mdata->Broadcaster());
582  currentMetadata->setChannel(mdata->Channel());
583  }
584 
585  // update the played tracks list to match the new metadata
586  if (m_playedTracksList)
587  {
588  for (int x = 0; x < m_playedTracksList->GetCount(); x++)
589  {
591  auto *playedmdata = item->GetData().value<MusicMetadata *>();
592 
593  if (playedmdata && playedmdata->ID() == id)
594  {
595  playedmdata->setBroadcaster(mdata->Broadcaster());
596  playedmdata->setChannel(mdata->Channel());
597 
598  InfoMap metadataMap;
599  playedmdata->toMap(metadataMap);
600  item->SetTextFromMap(metadataMap);
601  }
602  }
603  }
604 
605  // find the stream and make it the active item
606  for (int x = 0; x < m_streamList->GetCount(); x++)
607  {
609  auto *itemsdata = item->GetData().value<MusicMetadata *>();
610  if (itemsdata)
611  {
612  if (mdata->ID() == itemsdata->ID())
613  {
615  break;
616  }
617  }
618  }
619 }
620 
622 {
623  // sanity check this is a radio stream
624  int repo = ID_TO_REPO(mdata->ID());
625  if (repo != RT_Radio)
626  {
627  LOG(VB_GENERAL, LOG_ERR, "StreamView asked to delete a stream but it isn't a radio stream!");
628  return;
629  }
630 
631  int currPos = m_streamList->GetCurrentPos();
632  int topPos = m_streamList->GetTopItemPos();
633 
634  // if we are playing this radio stream stop playing
635  if (gPlayer->getCurrentMetadata() == mdata)
636  gPlayer->stop(true);
637 
639 
641 
643 
644  m_streamList->SetItemCurrent(currPos, topPos);
645 }
646 
648 
650 {
651  if (!LoadWindowFromXML("stream-ui.xml", "editstreammetadata", this))
652  return false;
653 
654  bool err = false;
655  UIUtilE::Assign(this, m_broadcasterEdit, "broadcasteredit", &err);
656  UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
657  UIUtilE::Assign(this, m_descEdit, "descriptionedit", &err);
658  UIUtilE::Assign(this, m_url1Edit, "url1edit", &err);
659  UIUtilE::Assign(this, m_url2Edit, "url2edit", &err);
660  UIUtilE::Assign(this, m_url3Edit, "url3edit", &err);
661  UIUtilE::Assign(this, m_url4Edit, "url4edit", &err);
662  UIUtilE::Assign(this, m_url5Edit, "url5edit", &err);
663  UIUtilE::Assign(this, m_logourlEdit, "logourledit" , &err);
664  UIUtilE::Assign(this, m_genreEdit, "genreedit", &err);
665  UIUtilE::Assign(this, m_languageEdit, "languageedit", &err);
666  UIUtilE::Assign(this, m_countryEdit, "countryedit", &err);
667  UIUtilE::Assign(this, m_formatEdit, "formatedit", &err);
668  UIUtilE::Assign(this, m_saveButton, "savebutton", &err);
669  UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
670  UIUtilE::Assign(this, m_searchButton, "searchbutton", &err);
671 
672  if (err)
673  {
674  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'editstreampopup'");
675  return false;
676  }
677 
678  if (m_streamMeta)
679  {
693  }
694  else
695  m_formatEdit->SetText("%a - %t");
696 
697  connect(m_searchButton, SIGNAL(Clicked()), this, SLOT(searchClicked()));
698  connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
699  connect(m_saveButton, SIGNAL(Clicked()), this, SLOT(saveClicked()));
700 
701  BuildFocusList();
702 
703  return true;
704 }
705 
707 {
709  MythScreenType *screen = new SearchStream(mainStack, this);
710 
711  if (screen->Create())
712  mainStack->AddScreen(screen);
713  else
714  delete screen;
715 
716 }
717 
719 {
720  bool doUpdate = true;
721 
722  if (!m_streamMeta)
723  {
726  doUpdate = false;
727  }
728 
736  m_streamMeta->setFormat("cast");
743 
744  if (doUpdate)
746  else
748 
749  Close();
750 }
751 
753 {
754  if (mdata)
755  {
757  m_channelEdit->SetText(mdata->Channel());
758  m_url1Edit->SetText(mdata->Url(0));
759  m_url2Edit->SetText(mdata->Url(1));
760  m_url3Edit->SetText(mdata->Url(2));
761  m_url4Edit->SetText(mdata->Url(3));
762  m_url5Edit->SetText(mdata->Url(4));
763  m_logourlEdit->SetText(mdata->LogoUrl());
764  m_genreEdit->SetText(mdata->Genre());
766  m_descEdit->SetText(mdata->Description());
767  m_countryEdit->SetText(mdata->Country());
768  m_languageEdit->SetText(mdata->Language());
769  }
770 }
771 
773 
775 {
776  if (!LoadWindowFromXML("stream-ui.xml", "searchstream", this))
777  return false;
778 
779  bool err = false;
780  UIUtilE::Assign(this, m_broadcasterList, "broadcasterlist", &err);
781  UIUtilE::Assign(this, m_genreList, "genrelist", &err);
782  UIUtilW::Assign(this, m_languageList, "languagelist", &err);
783  UIUtilW::Assign(this, m_countryList, "countrylist", &err);
784  UIUtilE::Assign(this, m_streamList, "streamlist", &err);
785  UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
786  UIUtilE::Assign(this, m_matchesText, "matchestext", &err);
787 
788  if (err)
789  {
790  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchstream'");
791  return false;
792  }
793 
796  m_matchesText->SetText("");
797 
798  connect(m_streamList, SIGNAL(itemClicked(MythUIButtonListItem*)),
799  this, SLOT(streamClicked(MythUIButtonListItem*)));
800  connect(m_streamList, SIGNAL(itemVisible(MythUIButtonListItem*)),
801  this, SLOT(streamVisible(MythUIButtonListItem*)));
802  connect(m_broadcasterList, SIGNAL(itemSelected(MythUIButtonListItem*)),
803  this, SLOT(updateStreams()));
804  connect(m_genreList, SIGNAL(itemSelected(MythUIButtonListItem*)),
805  this, SLOT(updateStreams()));
806  connect(m_countryList, SIGNAL(itemSelected(MythUIButtonListItem*)),
807  this, SLOT(updateStreams()));
808 
809 
810  if (m_countryList)
811  {
813  connect(m_languageList, SIGNAL(itemSelected(MythUIButtonListItem*)),
814  this, SLOT(updateStreams()));
815  }
816 
817  if (m_languageList)
818  {
820  connect(m_channelEdit, SIGNAL(valueChanged()),
821  this, SLOT(updateStreams()));
822  }
823 
824  connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(doUpdateStreams()));
825 
826  LoadInBackground("Loading Streams...");
827 
828  BuildFocusList();
829 
830  return true;
831 }
832 
834 {
835  loadStreams();
836  QTimer::singleShot(0, this, SLOT(doneLoading(void)));
837 }
838 
840 {
842  updateGenres();
843  updateLanguages();
844  updateCountries();
845  doUpdateStreams();
846 }
847 
849 {
850  if (!item)
851  return;
852 
853  MusicMetadata mdata = item->GetData().value<MusicMetadata>();
855 
856  Close();
857 }
858 
860 {
861  if (!item)
862  return;
863 
864  MusicMetadata mdata = item->GetData().value<MusicMetadata>();
865  if (!mdata.LogoUrl().isEmpty() && mdata.LogoUrl() != "-")
866  {
867  if (item->GetText("dummy") == " ")
868  {
869  item->SetImage(mdata.LogoUrl());
870  item->SetText("", "dummy");
871  }
872  }
873 }
874 
876 {
878 }
879 
881 {
883 
884  new MythUIButtonListItem(m_broadcasterList, tr("<All Broadcasters>"));
885 
886  MSqlQuery query(MSqlQuery::InitCon());
887 
888  query.prepare("SELECT DISTINCT broadcaster FROM music_streams ORDER BY broadcaster;");
889 
890  if (!query.exec() || !query.isActive())
891  {
892  MythDB::DBError("get broadcaster", query);
893  return;
894  }
895 
896  while (query.next())
897  {
898  new MythUIButtonListItem(m_broadcasterList, query.value(0).toString());
899  }
900 
901  m_broadcasterList->SetValue(tr("<All Broadcasters>"));
902 }
903 
905 {
906  m_genreList->Reset();
907 
908  new MythUIButtonListItem(m_genreList, tr("<All Genres>"));
909 
910  MSqlQuery query(MSqlQuery::InitCon());
911 
912  query.prepare("SELECT DISTINCT genre FROM music_streams ORDER BY genre;");
913 
914  if (!query.exec() || !query.isActive())
915  {
916  MythDB::DBError("get genres", query);
917  return;
918  }
919 
920  while (query.next())
921  {
922  new MythUIButtonListItem(m_genreList, query.value(0).toString());
923  }
924 
925  m_genreList->SetValue(tr("<All Genres>"));
926 }
927 
929 {
930  if (m_countryList)
931  {
932  m_countryList->Reset();
933 
934  new MythUIButtonListItem(m_countryList, tr("<All Countries>"));
935 
936  MSqlQuery query(MSqlQuery::InitCon());
937 
938  query.prepare("SELECT DISTINCT country FROM music_streams ORDER BY country;");
939 
940  if (!query.exec() || !query.isActive())
941  {
942  MythDB::DBError("get countries", query);
943  return;
944  }
945 
946  while (query.next())
947  {
948  new MythUIButtonListItem(m_countryList, query.value(0).toString());
949  }
950 
951  m_countryList->SetValue(tr("<All Countries>"));
952  }
953 }
954 
956 {
957  if (m_languageList)
958  {
960 
961  new MythUIButtonListItem(m_languageList, tr("<All Languages>"));
962 
963  MSqlQuery query(MSqlQuery::InitCon());
964 
965  query.prepare("SELECT DISTINCT language FROM music_streams ORDER BY language;");
966 
967  if (!query.exec() || !query.isActive())
968  {
969  MythDB::DBError("get languages", query);
970  return;
971  }
972 
973  while (query.next())
974  {
975  new MythUIButtonListItem(m_languageList, query.value(0).toString());
976  }
977 
978  m_languageList->SetValue(tr("<All Languages>"));
979  }
980 }
981 
983 {
984  if (m_updateTimer.isActive())
985  m_updateTimer.stop();
986 
987  m_updateTimer.start(500);
988 }
989 
991 {
992  if (m_updating)
993  return;
994 
995  QString broadcaster = m_broadcasterList->GetValue();
996  QString genre = m_genreList->GetValue();
997  QString language = m_languageList ? m_languageList->GetValue() : tr("<All Languages>");
998  QString country = m_countryList ? m_countryList->GetValue() : tr("<All Countries>");
999  QString channel = m_channelEdit->GetText();
1000 
1001  // only update the buttonlist if something changed
1002  if (m_oldBroadcaster == broadcaster && m_oldGenre == genre && m_oldChannel == channel &&
1003  m_oldLanguage == language && m_oldCountry == country)
1004  return;
1005 
1006  m_oldBroadcaster = broadcaster;
1007  m_oldGenre = genre;
1008  m_oldChannel = channel;
1009  m_oldLanguage = language;
1010  m_oldCountry = country;
1011 
1012  bool searchBroadcaster = (broadcaster != tr("<All Broadcasters>"));
1013  bool searchGenre = (genre != tr("<All Genres>"));
1014  bool searchLanguage = (language != tr("<All Languages>"));
1015  bool searchCountry = (country != tr("<All Countries>"));
1016  bool searchChannel = !channel.isEmpty();
1017 
1018  m_streams.clear();
1019  m_streamList->Reset();
1020 
1021  MSqlQuery query(MSqlQuery::InitCon());
1022 
1023  QString sql = "SELECT broadcaster, channel, description, genre, url1, url2, url3, url4, url5, "
1024  "logourl, metaformat, country, language "
1025  "FROM music_streams ";
1026  bool doneWhere = false;
1027 
1028  if (searchBroadcaster)
1029  {
1030  sql += "WHERE broadcaster = :BROADCASTER ";
1031  doneWhere = true;
1032  }
1033 
1034  if (searchGenre)
1035  {
1036  if (!doneWhere)
1037  {
1038  sql += "WHERE genre = :GENRE ";
1039  doneWhere = true;
1040  }
1041  else
1042  sql += "AND genre = :GENRE ";
1043  }
1044 
1045  if (searchLanguage)
1046  {
1047  if (!doneWhere)
1048  {
1049  sql += "WHERE language = :LANGUAGE ";
1050  doneWhere = true;
1051  }
1052  else
1053  sql += "AND language = :LANGUAGE ";
1054  }
1055 
1056  if (searchCountry)
1057  {
1058  if (!doneWhere)
1059  {
1060  sql += "WHERE country = :COUNTRY ";
1061  doneWhere = true;
1062  }
1063  else
1064  sql += "AND country = :COUNTRY ";
1065  }
1066 
1067  if (searchChannel)
1068  {
1069  if (!doneWhere)
1070  {
1071  sql += "WHERE channel LIKE " + QString("'%%1%'").arg(channel);
1072  // doneWhere = true;
1073  }
1074  else
1075  sql += "AND channel LIKE " + QString("'%%1%' ").arg(channel);
1076  }
1077 
1078  sql += "ORDER BY broadcaster, channel;";
1079 
1080  query.prepare(sql);
1081 
1082  if (searchBroadcaster)
1083  query.bindValue(":BROADCASTER", broadcaster);
1084 
1085  if (searchGenre)
1086  query.bindValue(":GENRE", genre);
1087 
1088  if (searchLanguage)
1089  query.bindValue(":LANGUAGE", language);
1090 
1091  if (searchCountry)
1092  query.bindValue(":COUNTRY", country);
1093 
1094  if (!query.exec() || !query.isActive())
1095  {
1096  MythDB::DBError("search streams", query);
1097  return;
1098  }
1099 
1100  if (query.size() > 500)
1101  {
1102  QString message = tr("Updating stream list. Please Wait ...");
1103  OpenBusyPopup(message);
1104  }
1105 
1106  int count = 0;
1107  while (query.next())
1108  {
1109  MusicMetadata mdata;
1110  mdata.setBroadcaster(query.value(0).toString());
1111  mdata.setChannel(query.value(1).toString());
1112  mdata.setDescription(query.value(2).toString());
1113  mdata.setGenre(query.value(3).toString());
1114 
1115  for (int x = 0; x < STREAMURLCOUNT; x++)
1116  mdata.setUrl(query.value(4 + x).toString(), x);
1117 
1118  mdata.setLogoUrl(query.value(9).toString());
1119  mdata.setMetadataFormat(query.value(10).toString());
1120  mdata.setCountry(query.value(11).toString());
1121  mdata.setLanguage(query.value(12).toString());
1122 
1123  auto *item = new MythUIButtonListItem(m_streamList, "",
1124  QVariant::fromValue(mdata));
1125  InfoMap metadataMap;
1126  mdata.toMap(metadataMap);
1127 
1128  item->SetTextFromMap(metadataMap);
1129 
1130  item->SetText(" ", "dummy");
1131  count++;
1132 
1133  if ((count % 500) == 0)
1134  {
1135  qApp->processEvents();
1136  }
1137  }
1138 
1139  m_matchesText->SetText(QString("%1").arg(m_streamList->GetCount()));
1140 
1141  if (query.size() > 500)
1142  CloseBusyPopup();
1143 
1144  m_updating = false;
1145 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
#define ID_TO_REPO(x)
Definition: musicmetadata.h:71
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1088
MythUIButtonList * m_streamList
Definition: streamview.h:48
void setPlayMode(PlayMode mode)
void SetUsed(int value)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
static void streamItemVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:495
QString m_oldCountry
Definition: streamview.h:131
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
MythUITextEdit * m_descEdit
Definition: streamview.h:81
QString Url(uint index=0)
Playlist * getCurrentPlaylist(void)
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
void deleteStream(MusicMetadata *mdata)
Definition: streamview.cpp:621
bool Create() override
Definition: streamview.cpp:649
void editStream(void)
Definition: streamview.cpp:376
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
static Type Playing
Definition: output.h:61
QString LogoUrl(void)
QString m_oldGenre
Definition: streamview.h:129
static Type MythEventMessage
Definition: mythevent.h:73
MythUITextEdit * m_url4Edit
Definition: streamview.h:85
QString Language(void)
MusicView m_currentView
Definition: musiccommon.h:139
virtual void SetValue(int value)
void updateStreams(void)
Definition: streamview.cpp:982
void updateStream(MusicMetadata *mdata)
uint32_t IdType
Definition: musicmetadata.h:86
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
int GetTopItemPos(void) const
QString Genre() const
virtual bool Create(void)
Basic menu dialog, message and a list of options.
void updateStreamList(void)
Definition: streamview.cpp:424
void addStream(MusicMetadata *mdata)
void setBroadcaster(const QString &broadcaster)
void setLanguage(const QString &language)
void customEvent(QEvent *event) override
MythUIButton * m_cancelButton
Definition: streamview.h:94
AllStream * m_all_streams
Definition: musicdata.h:56
MusicMetadata * m_lastStream
Definition: streamview.h:54
bool setCurrentTrackPos(int pos)
int size(void) const
Definition: mythdbcon.h:203
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
void changeStreamMetadata(MusicMetadata *mdata)
Definition: streamview.cpp:752
bool isPlaying(void)
Definition: musicplayer.h:102
MythUIText * m_noStreams
Definition: streamview.h:49
QString MetadataFormat(void)
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
Definition: streamview.cpp:833
MythScreenStack * GetStack(const QString &stackname)
MythUITextEdit * m_formatEdit
Definition: streamview.h:88
MythScreenStack * GetMainStack()
QString Country(void)
MythUIButtonListItem * GetItemAt(int pos) const
void setLogoUrl(const QString &logourl)
static MythThemedMenu * menu
QTimer m_updateTimer
Definition: streamview.h:142
MythUITextEdit * m_countryEdit
Definition: streamview.h:90
#define STREAMURLCOUNT
Definition: musicmetadata.h:76
void customEvent(QEvent *event) override
Definition: streamview.cpp:105
void BuildFocusList(void)
static Type Buffering
Definition: output.h:62
static Type kEventType
Definition: mythdialogbox.h:57
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
void reloadAlbumArtImages(void)
static Type TrackChangeEvent
Definition: musicplayer.h:40
QVariant value(int i) const
Definition: mythdbcon.h:198
virtual void Close()
void loadStreamPlaylist(void)
MythUIButtonListItem * GetItemByData(const QVariant &data)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: streamview.cpp:334
virtual void SetVisible(bool visible)
MythUIProgressBar * m_bufferProgress
Definition: streamview.h:51
void LoadInBackground(const QString &message="")
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
static bool updateStreamList(void)
QString m_oldChannel
Definition: streamview.h:130
MythUITextEdit * m_languageEdit
Definition: streamview.h:91
MusicMetadata * m_streamMeta
Definition: streamview.h:77
QString Channel(void)
QString m_oldLanguage
Definition: streamview.h:132
void streamItemClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:487
MythUIButtonList * m_streamList
Definition: streamview.h:139
MythUIButtonList * m_playedTracksList
Definition: musiccommon.h:204
MythUIText * m_matchesText
Definition: streamview.h:140
int getTrackCount(void)
Definition: playlist.h:82
MythUITextEdit * m_url1Edit
Definition: streamview.h:82
void updateTrackInfo(MusicMetadata *mdata)
MusicMetadata * getMetadata(MusicMetadata::IdType an_id)
IdType ID() const
void setChannel(const QString &channel)
void searchClicked(void)
Definition: streamview.cpp:706
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:83
QList< MusicMetadata * > & getPlayedTracksList(void)
Definition: musicplayer.h:130
bool isActive(void) const
Definition: mythdbcon.h:204
QString getAlbumArtFile(void)
void OpenBusyPopup(const QString &message="")
void SetTotal(int value)
static Type OperationStart
void setRepo(RepoType repo)
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
void SetText(const QString &text, const QString &name="", const QString &state="")
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
MythUIText * m_bufferStatus
Definition: streamview.h:50
void doUpdateStreams(void)
Definition: streamview.cpp:990
void updateBroadcasters(void)
Definition: streamview.cpp:880
void setFormat(const QString &lformat)
MythUIButtonList * m_languageList
Definition: streamview.h:137
void stop(bool stopAll=false)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
void updateLanguages(void)
Definition: streamview.cpp:955
void SetText(const QString &text, bool moveCursor=true)
MythUIType * GetFocusWidget(void) const
MythUIButtonList * m_genreList
Definition: streamview.h:135
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
MythMainWindow * GetMythMainWindow(void)
MythUITextEdit * m_channelEdit
Definition: streamview.h:80
QString GetText(const QString &name="") const
virtual QString GetValue() const
void setUrl(const QString &url, uint index=0)
EditStreamMetadata * m_parent
Definition: streamview.h:123
QString m_oldBroadcaster
Definition: streamview.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
MythUITextEdit * m_url5Edit
Definition: streamview.h:86
void streamClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:848
void CloseBusyPopup(void)
QString Description(void)
MusicMetadata * m_currStream
Definition: streamview.h:53
void updateStream(MusicMetadata *mdata)
Definition: streamview.cpp:549
MythUITextEdit * m_url2Edit
Definition: streamview.h:83
StreamView(MythScreenStack *parent, MythScreenType *parentScreen)
Definition: streamview.cpp:35
bool isPaused(void)
Definition: musicplayer.h:103
QList< MusicMetadata > m_streams
Definition: streamview.h:124
void updateGenres(void)
Definition: streamview.cpp:904
static void streamVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:859
void updateUIPlayedList(void)
void addStream(MusicMetadata *mdata)
Definition: streamview.cpp:515
void SetFontState(const QString &state, const QString &name="")
void setMetadataFormat(const QString &metaformat)
static Type BufferStatus
void setDescription(const QString &description)
void updateCountries(void)
Definition: streamview.cpp:928
MusicData * gMusicData
Definition: musicdata.cpp:20
MythUITextEdit * m_genreEdit
Definition: streamview.h:89
MythUITextEdit * m_logourlEdit
Definition: streamview.h:87
MythMenu * createSubMenu(void)
StreamView * m_parent
Definition: streamview.h:75
bool m_updating
Definition: streamview.h:143
void SetItemCurrent(MythUIButtonListItem *item)
static Type OperationStop
bool Create() override
Definition: streamview.cpp:774
static Type PlayedTracksChangedEvent
Definition: musicplayer.h:51
void removeStream(MusicMetadata *mdata)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
MythUIButton * m_searchButton
Definition: streamview.h:93
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
Screen in which all other widgets are contained and rendered.
void removeStream(void)
Definition: streamview.cpp:392
int GetCurrentPos() const
QString Broadcaster(void)
void saveClicked(void)
Definition: streamview.cpp:718
void DisplayState(const QString &state, const QString &name)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
bool Create(void) override
Definition: streamview.cpp:41
MythUIButtonList * m_countryList
Definition: streamview.h:136
void doneLoading(void)
Definition: streamview.cpp:839
MythUIButton * m_saveButton
Definition: streamview.h:95
MythUITextEdit * m_channelEdit
Definition: streamview.h:138
static void loadStreams(void)
Definition: streamview.cpp:875
void toMap(InfoMap &metadataMap, const QString &prefix="")
MythUITextEdit * m_url3Edit
Definition: streamview.h:84
void doRemoveStream(bool ok)
Definition: streamview.cpp:409
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
bool CreateCommon(void)
Definition: musiccommon.cpp:81
QString GetText(void) const
void ShowMenu(void) override
Definition: streamview.cpp:79
void SetValueByData(const QVariant &data)
MythUIButtonListItem * GetItemCurrent() const
MythUITextEdit * m_broadcasterEdit
Definition: streamview.h:79
static Type Stopped
Definition: output.h:65
void setCountry(const QString &country)
void setGenre(const QString &lgenre)
MythUIButtonList * m_broadcasterList
Definition: streamview.h:134
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:41