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"), qVariantFromValue((int)MV_VISUALIZER));
91  menu->AddItem(MusicCommon::tr("Lyrics"), qVariantFromValue((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  qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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(qVariantFromValue(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, maxSize = 0;
269  dhe->getBufferStatus(&available, &maxSize);
270 
271  if (m_bufferStatus)
272  {
273  QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
274  m_bufferStatus->SetText(status);
275  }
276 
277  if (m_bufferProgress)
278  {
279  m_bufferProgress->SetTotal(maxSize);
280  m_bufferProgress->SetUsed(available);
281  }
282  }
283  else if (event->type() == DecoderHandlerEvent::OperationStop)
284  {
285  if (m_bufferStatus)
287  }
288  else if (event->type() == DialogCompletionEvent::kEventType)
289  {
290  auto dce = dynamic_cast<DialogCompletionEvent*>(event);
291 
292  // make sure the user didn't ESCAPE out of the menu
293  if ((dce == nullptr) || (dce->GetResult() < 0))
294  return;
295 
296  QString resultid = dce->GetId();
297  QString resulttext = dce->GetResultText();
298 
299  if (resultid == "mainmenu")
300  {
301  if (resulttext == tr("Add Stream"))
302  {
304  MythScreenType *screen = new EditStreamMetadata(mainStack, this, nullptr);
305 
306  if (screen->Create())
307  mainStack->AddScreen(screen);
308  else
309  delete screen;
310  }
311  else if (resulttext == tr("Remove Stream"))
312  {
313  removeStream();
314  }
315  else if (resulttext == tr("Edit Stream"))
316  {
317  editStream();
318  }
319  else
320  handled = false;
321  }
322  else
323  handled = false;
324  }
325  else
326  handled = false;
327 
328 
329  if (!handled)
331 }
332 
333 bool StreamView::keyPressEvent(QKeyEvent *event)
334 {
335  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
336  return true;
337 
338  QStringList actions;
339  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
340 
341  for (int i = 0; i < actions.size() && !handled; i++)
342  {
343  QString action = actions[i];
344  handled = true;
345 
346  if (action == "EDIT")
347  {
348  editStream();
349  }
350  else if (action == "DELETE")
351  {
352  removeStream();
353  }
354  else if (action == "TOGGLELAST")
355  {
357  {
358  m_streamList->SetValueByData(qVariantFromValue(m_lastStream));
359 
361  if (item)
362  streamItemClicked(item);
363  }
364  }
365  else
366  handled = false;
367  }
368 
369  if (!handled && MusicCommon::keyPressEvent(event))
370  handled = true;
371 
372  return handled;
373 }
374 
376 {
378  if (item)
379  {
380  auto *mdata = item->GetData().value<MusicMetadata *>();
382  MythScreenType *screen = new EditStreamMetadata(mainStack, this, mdata);
383 
384  if (screen->Create())
385  mainStack->AddScreen(screen);
386  else
387  delete screen;
388  }
389 }
390 
392 {
394  if (item)
395  {
396  auto *mdata = item->GetData().value<MusicMetadata *>();
397 
398  if (mdata)
399  ShowOkPopup(tr("Are you sure you want to delete this Stream?\n"
400  "Broadcaster: %1 - Channel: %2")
401  .arg(mdata->Broadcaster()).arg(mdata->Channel()),
402  this, SLOT(doRemoveStream(bool)), true);
403  }
404 }
405 
407 {
408  if (!ok)
409  return;
410 
412  if (item)
413  {
414  auto *mdata = item->GetData().value<MusicMetadata *>();
415 
416  if (mdata)
417  deleteStream(mdata);
418  }
419 }
420 
422 {
423  if (!gPlayer->getCurrentPlaylist())
424  return;
425 
426  m_streamList->Reset();
427 
428  bool foundActiveStream = false;
429 
430  for (int x = 0; x < gPlayer->getCurrentPlaylist()->getTrackCount(); x++)
431  {
433  auto *item = new MythUIButtonListItem(m_streamList, "",
434  qVariantFromValue(mdata));
435  InfoMap metadataMap;
436  if (mdata)
437  mdata->toMap(metadataMap);
438  item->SetTextFromMap(metadataMap);
439  item->SetText("", "imageloaded");
440  item->SetFontState("normal");
441  item->DisplayState("default", "playstate");
442 
443  // if this is the current radio stream update its play state to match the player
444  if (gPlayer->getCurrentMetadata() && mdata &&
445  mdata->ID() == gPlayer->getCurrentMetadata()->ID())
446  {
447  if (gPlayer->isPlaying())
448  {
449  item->SetFontState("running");
450  item->DisplayState("playing", "playstate");
451  }
452  else if (gPlayer->isPaused())
453  {
454  item->SetFontState("idle");
455  item->DisplayState("paused", "playstate");
456  }
457  else
458  {
459  item->SetFontState("normal");
460  item->DisplayState("stopped", "playstate");
461  }
462 
464 
466 
467  foundActiveStream = true;
468  }
469  }
470 
471  if (m_streamList->GetCount() > 0 && !foundActiveStream)
472  {
474  gPlayer->stop(true);
475  }
476 
477  if (m_noStreams)
479 
480  if (m_streamList->GetCount() == 0)
481  LOG(VB_GENERAL, LOG_ERR, "StreamView hasn't found any streams!");
482 }
483 
485 {
486  if (!item)
487  return;
488 
490 }
491 
493 {
494  if (!item)
495  return;
496 
497  if (!item->GetText("imageloaded").isEmpty())
498  return;
499 
500  auto *mdata = item->GetData().value<MusicMetadata *>();
501  if (mdata)
502  {
503  if (!mdata->LogoUrl().isEmpty())
504  item->SetImage(mdata->getAlbumArtFile());
505  else
506  item->SetImage("");
507  }
508 
509  item->SetText(" ", "imageloaded");
510 }
511 
513 {
514  // sanity check this is a radio stream
515  int repo = ID_TO_REPO(mdata->ID());
516  if (repo != RT_Radio)
517  {
518  LOG(VB_GENERAL, LOG_ERR, "StreamView asked to add a stream but it isn't a radio stream!");
519  return;
520  }
521 
522  QString url = mdata->Url();
523 
525 
527 
529 
530  // find the new stream and make it the active item
531  for (int x = 0; x < m_streamList->GetCount(); x++)
532  {
534  auto *itemsdata = item->GetData().value<MusicMetadata *>();
535  if (itemsdata)
536  {
537  if (url == itemsdata->Url())
538  {
540  break;
541  }
542  }
543  }
544 }
545 
547 {
548  // sanity check this is a radio stream
549  int repo = ID_TO_REPO(mdata->ID());
550  if (repo != RT_Radio)
551  {
552  LOG(VB_GENERAL, LOG_ERR, "StreamView asked to update a stream but it isn't a radio stream!");
553  return;
554  }
555 
556  MusicMetadata::IdType id = mdata->ID();
557 
559 
561 
562  // update mdata to point to the new item
563  mdata = gMusicData->m_all_streams->getMetadata(id);
564 
565  if (!mdata)
566  return;
567 
568  // force the icon to reload incase it changed
569  QFile::remove(mdata->getAlbumArtFile());
570  mdata->reloadAlbumArtImages();
571 
573 
574  // if we just edited the currently playing stream update the current metadata to match
575  MusicMetadata *currentMetadata = gPlayer->getCurrentMetadata();
576  if (id == currentMetadata->ID())
577  {
578  currentMetadata->setBroadcaster(mdata->Broadcaster());
579  currentMetadata->setChannel(mdata->Channel());
580  }
581 
582  // update the played tracks list to match the new metadata
583  if (m_playedTracksList)
584  {
585  for (int x = 0; x < m_playedTracksList->GetCount(); x++)
586  {
588  auto *playedmdata = item->GetData().value<MusicMetadata *>();
589 
590  if (playedmdata && playedmdata->ID() == id)
591  {
592  playedmdata->setBroadcaster(mdata->Broadcaster());
593  playedmdata->setChannel(mdata->Channel());
594 
595  InfoMap metadataMap;
596  playedmdata->toMap(metadataMap);
597  item->SetTextFromMap(metadataMap);
598  }
599  }
600  }
601 
602  // find the stream and make it the active item
603  for (int x = 0; x < m_streamList->GetCount(); x++)
604  {
606  auto *itemsdata = item->GetData().value<MusicMetadata *>();
607  if (itemsdata)
608  {
609  if (mdata->ID() == itemsdata->ID())
610  {
612  break;
613  }
614  }
615  }
616 }
617 
619 {
620  // sanity check this is a radio stream
621  int repo = ID_TO_REPO(mdata->ID());
622  if (repo != RT_Radio)
623  {
624  LOG(VB_GENERAL, LOG_ERR, "StreamView asked to delete a stream but it isn't a radio stream!");
625  return;
626  }
627 
628  int currPos = m_streamList->GetCurrentPos();
629  int topPos = m_streamList->GetTopItemPos();
630 
631  // if we are playing this radio stream stop playing
632  if (gPlayer->getCurrentMetadata() == mdata)
633  gPlayer->stop(true);
634 
636 
638 
640 
641  m_streamList->SetItemCurrent(currPos, topPos);
642 }
643 
645 
647 {
648  if (!LoadWindowFromXML("stream-ui.xml", "editstreammetadata", this))
649  return false;
650 
651  bool err = false;
652  UIUtilE::Assign(this, m_broadcasterEdit, "broadcasteredit", &err);
653  UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
654  UIUtilE::Assign(this, m_descEdit, "descriptionedit", &err);
655  UIUtilE::Assign(this, m_url1Edit, "url1edit", &err);
656  UIUtilE::Assign(this, m_url2Edit, "url2edit", &err);
657  UIUtilE::Assign(this, m_url3Edit, "url3edit", &err);
658  UIUtilE::Assign(this, m_url4Edit, "url4edit", &err);
659  UIUtilE::Assign(this, m_url5Edit, "url5edit", &err);
660  UIUtilE::Assign(this, m_logourlEdit, "logourledit" , &err);
661  UIUtilE::Assign(this, m_genreEdit, "genreedit", &err);
662  UIUtilE::Assign(this, m_languageEdit, "languageedit", &err);
663  UIUtilE::Assign(this, m_countryEdit, "countryedit", &err);
664  UIUtilE::Assign(this, m_formatEdit, "formatedit", &err);
665  UIUtilE::Assign(this, m_saveButton, "savebutton", &err);
666  UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
667  UIUtilE::Assign(this, m_searchButton, "searchbutton", &err);
668 
669  if (err)
670  {
671  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'editstreampopup'");
672  return false;
673  }
674 
675  if (m_streamMeta)
676  {
690  }
691  else
692  m_formatEdit->SetText("%a - %t");
693 
694  connect(m_searchButton, SIGNAL(Clicked()), this, SLOT(searchClicked()));
695  connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
696  connect(m_saveButton, SIGNAL(Clicked()), this, SLOT(saveClicked()));
697 
698  BuildFocusList();
699 
700  return true;
701 }
702 
704 {
706  MythScreenType *screen = new SearchStream(mainStack, this);
707 
708  if (screen->Create())
709  mainStack->AddScreen(screen);
710  else
711  delete screen;
712 
713 }
714 
716 {
717  bool doUpdate = true;
718 
719  if (!m_streamMeta)
720  {
723  doUpdate = false;
724  }
725 
733  m_streamMeta->setFormat("cast");
740 
741  if (doUpdate)
743  else
745 
746  Close();
747 }
748 
750 {
751  if (mdata)
752  {
754  m_channelEdit->SetText(mdata->Channel());
755  m_url1Edit->SetText(mdata->Url(0));
756  m_url2Edit->SetText(mdata->Url(1));
757  m_url3Edit->SetText(mdata->Url(2));
758  m_url4Edit->SetText(mdata->Url(3));
759  m_url5Edit->SetText(mdata->Url(4));
760  m_logourlEdit->SetText(mdata->LogoUrl());
761  m_genreEdit->SetText(mdata->Genre());
763  m_descEdit->SetText(mdata->Description());
764  m_countryEdit->SetText(mdata->Country());
765  m_languageEdit->SetText(mdata->Language());
766  }
767 }
768 
770 
772 {
773  if (!LoadWindowFromXML("stream-ui.xml", "searchstream", this))
774  return false;
775 
776  bool err = false;
777  UIUtilE::Assign(this, m_broadcasterList, "broadcasterlist", &err);
778  UIUtilE::Assign(this, m_genreList, "genrelist", &err);
779  UIUtilW::Assign(this, m_languageList, "languagelist", &err);
780  UIUtilW::Assign(this, m_countryList, "countrylist", &err);
781  UIUtilE::Assign(this, m_streamList, "streamlist", &err);
782  UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
783  UIUtilE::Assign(this, m_matchesText, "matchestext", &err);
784 
785  if (err)
786  {
787  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchstream'");
788  return false;
789  }
790 
793  m_matchesText->SetText("");
794 
795  connect(m_streamList, SIGNAL(itemClicked(MythUIButtonListItem*)),
796  this, SLOT(streamClicked(MythUIButtonListItem*)));
797  connect(m_streamList, SIGNAL(itemVisible(MythUIButtonListItem*)),
798  this, SLOT(streamVisible(MythUIButtonListItem*)));
799  connect(m_broadcasterList, SIGNAL(itemSelected(MythUIButtonListItem*)),
800  this, SLOT(updateStreams()));
801  connect(m_genreList, SIGNAL(itemSelected(MythUIButtonListItem*)),
802  this, SLOT(updateStreams()));
803  connect(m_countryList, SIGNAL(itemSelected(MythUIButtonListItem*)),
804  this, SLOT(updateStreams()));
805 
806 
807  if (m_countryList)
808  {
810  connect(m_languageList, SIGNAL(itemSelected(MythUIButtonListItem*)),
811  this, SLOT(updateStreams()));
812  }
813 
814  if (m_languageList)
815  {
817  connect(m_channelEdit, SIGNAL(valueChanged()),
818  this, SLOT(updateStreams()));
819  }
820 
821  connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(doUpdateStreams()));
822 
823  LoadInBackground("Loading Streams...");
824 
825  BuildFocusList();
826 
827  return true;
828 }
829 
831 {
832  loadStreams();
833  QTimer::singleShot(0, this, SLOT(doneLoading(void)));
834 }
835 
837 {
839  updateGenres();
840  updateLanguages();
841  updateCountries();
842  doUpdateStreams();
843 }
844 
846 {
847  if (!item)
848  return;
849 
850  MusicMetadata mdata = item->GetData().value<MusicMetadata>();
852 
853  Close();
854 }
855 
857 {
858  if (!item)
859  return;
860 
861  MusicMetadata mdata = item->GetData().value<MusicMetadata>();
862  if (!mdata.LogoUrl().isEmpty() && mdata.LogoUrl() != "-")
863  {
864  if (item->GetText("dummy") == " ")
865  {
866  item->SetImage(mdata.LogoUrl());
867  item->SetText("", "dummy");
868  }
869  }
870 }
871 
873 {
875 }
876 
878 {
880 
881  new MythUIButtonListItem(m_broadcasterList, tr("<All Broadcasters>"));
882 
883  MSqlQuery query(MSqlQuery::InitCon());
884 
885  query.prepare("SELECT DISTINCT broadcaster FROM music_streams ORDER BY broadcaster;");
886 
887  if (!query.exec() || !query.isActive())
888  {
889  MythDB::DBError("get broadcaster", query);
890  return;
891  }
892 
893  while (query.next())
894  {
895  new MythUIButtonListItem(m_broadcasterList, query.value(0).toString());
896  }
897 
898  m_broadcasterList->SetValue(tr("<All Broadcasters>"));
899 }
900 
902 {
903  m_genreList->Reset();
904 
905  new MythUIButtonListItem(m_genreList, tr("<All Genres>"));
906 
907  MSqlQuery query(MSqlQuery::InitCon());
908 
909  query.prepare("SELECT DISTINCT genre FROM music_streams ORDER BY genre;");
910 
911  if (!query.exec() || !query.isActive())
912  {
913  MythDB::DBError("get genres", query);
914  return;
915  }
916 
917  while (query.next())
918  {
919  new MythUIButtonListItem(m_genreList, query.value(0).toString());
920  }
921 
922  m_genreList->SetValue(tr("<All Genres>"));
923 }
924 
926 {
927  if (m_countryList)
928  {
929  m_countryList->Reset();
930 
931  new MythUIButtonListItem(m_countryList, tr("<All Countries>"));
932 
933  MSqlQuery query(MSqlQuery::InitCon());
934 
935  query.prepare("SELECT DISTINCT country FROM music_streams ORDER BY country;");
936 
937  if (!query.exec() || !query.isActive())
938  {
939  MythDB::DBError("get countries", query);
940  return;
941  }
942 
943  while (query.next())
944  {
945  new MythUIButtonListItem(m_countryList, query.value(0).toString());
946  }
947 
948  m_countryList->SetValue(tr("<All Countries>"));
949  }
950 }
951 
953 {
954  if (m_languageList)
955  {
957 
958  new MythUIButtonListItem(m_languageList, tr("<All Languages>"));
959 
960  MSqlQuery query(MSqlQuery::InitCon());
961 
962  query.prepare("SELECT DISTINCT language FROM music_streams ORDER BY language;");
963 
964  if (!query.exec() || !query.isActive())
965  {
966  MythDB::DBError("get languages", query);
967  return;
968  }
969 
970  while (query.next())
971  {
972  new MythUIButtonListItem(m_languageList, query.value(0).toString());
973  }
974 
975  m_languageList->SetValue(tr("<All Languages>"));
976  }
977 }
978 
980 {
981  if (m_updateTimer.isActive())
982  m_updateTimer.stop();
983 
984  m_updateTimer.start(500);
985 }
986 
988 {
989  if (m_updating)
990  return;
991 
992  QString broadcaster = m_broadcasterList->GetValue();
993  QString genre = m_genreList->GetValue();
994  QString language = m_languageList ? m_languageList->GetValue() : tr("<All Languages>");
995  QString country = m_countryList ? m_countryList->GetValue() : tr("<All Countries>");
996  QString channel = m_channelEdit->GetText();
997 
998  // only update the buttonlist if something changed
999  if (m_oldBroadcaster == broadcaster && m_oldGenre == genre && m_oldChannel == channel &&
1000  m_oldLanguage == language && m_oldCountry == country)
1001  return;
1002 
1003  m_oldBroadcaster = broadcaster;
1004  m_oldGenre = genre;
1005  m_oldChannel = channel;
1006  m_oldLanguage = language;
1007  m_oldCountry = country;
1008 
1009  bool searchBroadcaster = (broadcaster != tr("<All Broadcasters>"));
1010  bool searchGenre = (genre != tr("<All Genres>"));
1011  bool searchLanguage = (language != tr("<All Languages>"));
1012  bool searchCountry = (country != tr("<All Countries>"));
1013  bool searchChannel = !channel.isEmpty();
1014 
1015  m_streams.clear();
1016  m_streamList->Reset();
1017 
1018  MSqlQuery query(MSqlQuery::InitCon());
1019 
1020  QString sql = "SELECT broadcaster, channel, description, genre, url1, url2, url3, url4, url5, "
1021  "logourl, metaformat, country, language "
1022  "FROM music_streams ";
1023  bool doneWhere = false;
1024 
1025  if (searchBroadcaster)
1026  {
1027  sql += "WHERE broadcaster = :BROADCASTER ";
1028  doneWhere = true;
1029  }
1030 
1031  if (searchGenre)
1032  {
1033  if (!doneWhere)
1034  {
1035  sql += "WHERE genre = :GENRE ";
1036  doneWhere = true;
1037  }
1038  else
1039  sql += "AND genre = :GENRE ";
1040  }
1041 
1042  if (searchLanguage)
1043  {
1044  if (!doneWhere)
1045  {
1046  sql += "WHERE language = :LANGUAGE ";
1047  doneWhere = true;
1048  }
1049  else
1050  sql += "AND language = :LANGUAGE ";
1051  }
1052 
1053  if (searchCountry)
1054  {
1055  if (!doneWhere)
1056  {
1057  sql += "WHERE country = :COUNTRY ";
1058  doneWhere = true;
1059  }
1060  else
1061  sql += "AND country = :COUNTRY ";
1062  }
1063 
1064  if (searchChannel)
1065  {
1066  if (!doneWhere)
1067  {
1068  sql += "WHERE channel LIKE " + QString("'%%1%'").arg(channel);
1069  // doneWhere = true;
1070  }
1071  else
1072  sql += "AND channel LIKE " + QString("'%%1%' ").arg(channel);
1073  }
1074 
1075  sql += "ORDER BY broadcaster, channel;";
1076 
1077  query.prepare(sql);
1078 
1079  if (searchBroadcaster)
1080  query.bindValue(":BROADCASTER", broadcaster);
1081 
1082  if (searchGenre)
1083  query.bindValue(":GENRE", genre);
1084 
1085  if (searchLanguage)
1086  query.bindValue(":LANGUAGE", language);
1087 
1088  if (searchCountry)
1089  query.bindValue(":COUNTRY", country);
1090 
1091  if (!query.exec() || !query.isActive())
1092  {
1093  MythDB::DBError("search streams", query);
1094  return;
1095  }
1096 
1097  if (query.size() > 500)
1098  {
1099  QString message = tr("Updating stream list. Please Wait ...");
1100  OpenBusyPopup(message);
1101  }
1102 
1103  int count = 0;
1104  while (query.next())
1105  {
1106  MusicMetadata mdata;
1107  mdata.setBroadcaster(query.value(0).toString());
1108  mdata.setChannel(query.value(1).toString());
1109  mdata.setDescription(query.value(2).toString());
1110  mdata.setGenre(query.value(3).toString());
1111 
1112  for (int x = 0; x < STREAMURLCOUNT; x++)
1113  mdata.setUrl(query.value(4 + x).toString(), x);
1114 
1115  mdata.setLogoUrl(query.value(9).toString());
1116  mdata.setMetadataFormat(query.value(10).toString());
1117  mdata.setCountry(query.value(11).toString());
1118  mdata.setLanguage(query.value(12).toString());
1119 
1120  auto *item = new MythUIButtonListItem(m_streamList, "",
1121  qVariantFromValue(mdata));
1122  InfoMap metadataMap;
1123  mdata.toMap(metadataMap);
1124 
1125  item->SetTextFromMap(metadataMap);
1126 
1127  item->SetText(" ", "dummy");
1128  count++;
1129 
1130  if ((count % 500) == 0)
1131  {
1132  qApp->processEvents();
1133  }
1134  }
1135 
1136  m_matchesText->SetText(QString("%1").arg(m_streamList->GetCount()));
1137 
1138  if (query.size() > 500)
1139  CloseBusyPopup();
1140 
1141  m_updating = false;
1142 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:781
#define ID_TO_REPO(x)
Definition: musicmetadata.h:69
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1084
MythUIButtonList * m_streamList
Definition: streamview.h:48
void setPlayMode(PlayMode mode)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:862
static void streamItemVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:492
QString m_oldCountry
Definition: streamview.h:131
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
bool keyPressEvent(QKeyEvent *) override
Key event handler.
Definition: streamview.cpp:333
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:618
bool Create() override
Definition: streamview.cpp:646
void editStream(void)
Definition: streamview.cpp:375
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:66
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:979
void updateStream(MusicMetadata *mdata)
uint32_t IdType
Definition: musicmetadata.h:84
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:421
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:55
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:749
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:830
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:74
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:50
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)
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:484
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:79
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:703
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="")
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=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:534
MythUIText * m_bufferStatus
Definition: streamview.h:50
void doUpdateStreams(void)
Definition: streamview.cpp:987
void updateBroadcasters(void)
Definition: streamview.cpp:877
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:952
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:806
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
MythUITextEdit * m_url5Edit
Definition: streamview.h:86
void streamClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:845
void CloseBusyPopup(void)
QString Description(void)
MusicMetadata * m_currStream
Definition: streamview.h:53
void updateStream(MusicMetadata *mdata)
Definition: streamview.cpp:546
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:901
static void streamVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:856
void updateUIPlayedList(void)
void addStream(MusicMetadata *mdata)
Definition: streamview.cpp:512
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:925
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:771
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:602
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:391
int GetCurrentPos() const
QString Broadcaster(void)
void saveClicked(void)
Definition: streamview.cpp:715
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:836
MythUIButton * m_saveButton
Definition: streamview.h:95
MythUITextEdit * m_channelEdit
Definition: streamview.h:138
static void loadStreams(void)
Definition: streamview.cpp:872
void toMap(InfoMap &metadataMap, const QString &prefix="")
MythUITextEdit * m_url3Edit
Definition: streamview.h:84
void doRemoveStream(bool ok)
Definition: streamview.cpp:406
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