MythTV  master
musiccommon.cpp
Go to the documentation of this file.
1 // ANSI C includes
2 #include <cstdlib>
3 
4 // C++ includes
5 #include <iostream>
6 using namespace std;
7 
8 // Qt includes
9 #include <QApplication>
10 #include <QLocale>
11 
12 // mythtv
13 #include <mythuitextedit.h>
14 #include <mythuistatetype.h>
15 #include <mythuiprogressbar.h>
16 #include <mythuibutton.h>
17 #include <mythuiimage.h>
18 #include <mythdialogbox.h>
19 #include <mythuibuttonlist.h>
20 #include <mythuibuttontree.h>
21 #include <mythuicheckbox.h>
22 #include <mythuivideo.h>
23 #include <mythuitext.h>
24 #include <audiooutput.h>
25 #include <compat.h>
26 #include <lcddevice.h>
27 #include <musicmetadata.h>
28 
29 // MythMusic includes
30 #include "musicdata.h"
31 #include "constants.h"
32 #include "decoder.h"
33 #include "mainvisual.h"
34 #include "smartplaylist.h"
35 #include "playlistcontainer.h"
36 #include "search.h"
37 #include "editmetadata.h"
38 #include "playlist.h"
39 
40 #include "musiccommon.h"
41 #include "playlistview.h"
42 #include "playlisteditorview.h"
43 #include "streamview.h"
44 #include "visualizerview.h"
45 #include "searchview.h"
46 #include "lyricsview.h"
47 
49  const QString &name)
50  : MythScreenType(parent, name),
51  m_parentScreen(parentScreen),
52  m_currentView()
53 {
54  m_cycleVisualizer = gCoreContext->GetBoolSetting("VisualCycleOnSongChange", false);
55 
56  if (LCD *lcd = LCD::Get())
57  {
58  lcd->switchToTime();
59  lcd->setFunctionLEDs(FUNC_MUSIC, true);
60  }
61 }
62 
64 {
65  gPlayer->removeListener(this);
66 
67  if (m_mainvisual)
68  {
70  delete m_mainvisual;
71  m_mainvisual = nullptr;
72  }
73 
74  if (LCD *lcd = LCD::Get())
75  {
76  lcd->switchToTime();
77  lcd->setFunctionLEDs(FUNC_MUSIC, false);
78  }
79 }
80 
82 {
83  bool err = false;
84  UIUtilW::Assign(this, m_timeText, "time", &err);
85  UIUtilW::Assign(this, m_infoText, "info", &err);
86  UIUtilW::Assign(this, m_visualText, "visualizername", &err);
87  UIUtilW::Assign(this, m_noTracksText, "notracks", &err);
88 
89  UIUtilW::Assign(this, m_shuffleState, "shufflestate", &err);
90  UIUtilW::Assign(this, m_repeatState, "repeatstate", &err);
91  UIUtilW::Assign(this, m_movingTracksState, "movingtracksstate", &err);
92 
93  UIUtilW::Assign(this, m_ratingState, "ratingstate", &err);
94 
95  UIUtilW::Assign(this, m_trackProgress, "progress", &err);
96  UIUtilW::Assign(this, m_trackProgressText, "trackprogress", &err);
97  UIUtilW::Assign(this, m_trackSpeedText, "trackspeed", &err);
98  UIUtilW::Assign(this, m_trackState, "trackstate", &err);
99 
100  UIUtilW::Assign(this, m_volumeText, "volume", &err);
101  UIUtilW::Assign(this, m_muteState, "mutestate", &err);
102 
103  UIUtilW::Assign(this, m_playlistProgress, "playlistprogress", &err);
104 
105  UIUtilW::Assign(this, m_prevButton, "prev", &err);
106  UIUtilW::Assign(this, m_rewButton, "rew", &err);
107  UIUtilW::Assign(this, m_pauseButton, "pause", &err);
108  UIUtilW::Assign(this, m_playButton, "play", &err);
109  UIUtilW::Assign(this, m_stopButton, "stop", &err);
110  UIUtilW::Assign(this, m_ffButton, "ff", &err);
111  UIUtilW::Assign(this, m_nextButton, "next", &err);
112 
113  UIUtilW::Assign(this, m_coverartImage, "coverart", &err);
114 
115  UIUtilW::Assign(this, m_currentPlaylist, "currentplaylist", &err);
116  UIUtilW::Assign(this, m_playedTracksList, "playedtrackslist", &err);
117 
118  UIUtilW::Assign(this, m_visualizerVideo, "visualizer", &err);
119 
120  if (m_prevButton)
121  connect(m_prevButton, SIGNAL(Clicked()), this, SLOT(previous()));
122 
123  if (m_rewButton)
124  connect(m_rewButton, SIGNAL(Clicked()), this, SLOT(seekback()));
125 
126  if (m_pauseButton)
127  {
128  m_pauseButton->SetLockable(true);
129  connect(m_pauseButton, SIGNAL(Clicked()), this, SLOT(pause()));
130  }
131 
132  if (m_playButton)
133  {
134  m_playButton->SetLockable(true);
135  connect(m_playButton, SIGNAL(Clicked()), this, SLOT(play()));
136  }
137 
138  if (m_stopButton)
139  {
140  m_stopButton->SetLockable(true);
141  connect(m_stopButton, SIGNAL(Clicked()), this, SLOT(stop()));
142  }
143 
144  if (m_ffButton)
145  connect(m_ffButton, SIGNAL(Clicked()), this, SLOT(seekforward()));
146 
147  if (m_nextButton)
148  connect(m_nextButton, SIGNAL(Clicked()), this, SLOT(next()));
149 
150  if (m_currentPlaylist)
151  {
152  connect(m_currentPlaylist, SIGNAL(itemClicked(MythUIButtonListItem*)),
154  connect(m_currentPlaylist, SIGNAL(itemVisible(MythUIButtonListItem*)),
156 
157  m_currentPlaylist->SetSearchFields("**search**");
158  }
159 
160  init();
161 
162  return err;
163 }
164 
166 {
167  gPlayer->addListener(this);
168 
169  if (startPlayback)
170  {
171  if (!gPlayer->isPlaying())
172  {
173  if (m_currentView == MV_RADIO)
177  else
179 
181  }
182  else
183  {
184  // if we are playing but we are switching to a view from a different playmode
185  // we need to restart playback in the new mode
187  {
188  // these views can be used in both play modes
189  }
191  {
192  gPlayer->stop(true);
193 
196  else
198 
200  }
202  {
203  gPlayer->stop(true);
206  }
207  }
208  }
209 
211 
213  if (curMeta)
214  updateTrackInfo(curMeta);
215 
217 
218  if (m_currentPlaylist)
220 
221  if (m_visualizerVideo)
222  {
224 
226 
227  m_fullscreenBlank = false;
228 
229  m_randomVisualizer = gCoreContext->GetBoolSetting("VisualRandomize", false);
230 
232 
233  // sanity check
234  if (m_currentVisual >= static_cast<uint>(m_visualModes.count()))
235  {
236  LOG(VB_GENERAL, LOG_ERR, QString("MusicCommon: Got a bad saved visualizer: %1").arg(m_currentVisual));
237  m_currentVisual = 0;
238  }
239 
241 
242  if (gPlayer->isPlaying())
243  startVisualizer();
244  }
245 
246  m_controlVolume = gCoreContext->GetBoolSetting("MythControlsVolume", false);
247  updateVolume();
248 
251 
252  if (m_stopButton)
254  if (m_playButton)
256  if (m_pauseButton)
258  if (m_trackState)
259  {
260  if (gPlayer->isPlaying())
261  m_trackState->DisplayState("playing");
262  else if (gPlayer->isPaused())
263  m_trackState->DisplayState("paused");
264  else
265  m_trackState->DisplayState("stopped");
266 
267  }
268 
271 
275 
276  if (m_playlistProgress)
277  {
280  }
281 
283 
285 }
286 
288 {
289  if (m_repeatState)
290  {
291  switch (gPlayer->getRepeatMode())
292  {
294  m_repeatState->DisplayState("off");
295  if (class LCD *lcd = LCD::Get())
296  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_NONE);
297  break;
299  m_repeatState->DisplayState("track");
300  if (class LCD *lcd = LCD::Get())
301  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_TRACK);
302  break;
304  m_repeatState->DisplayState("all");
305  if (class LCD *lcd = LCD::Get())
306  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_ALL);
307  break;
308  default:
309  m_repeatState->DisplayState("off");
310  if (class LCD *lcd = LCD::Get())
311  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_NONE);
312  break;
313  }
314  }
315 
316  // need this to update the next track info
318  if (curMeta)
319  updateTrackInfo(curMeta);
320 }
321 
322 void MusicCommon::updateShuffleMode(bool updateUIList)
323 {
324  if (m_shuffleState)
325  {
326  switch (gPlayer->getShuffleMode())
327  {
330  if (class LCD *lcd = LCD::Get())
331  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_NONE);
332  break;
334  m_shuffleState->DisplayState("random");
335  if (class LCD *lcd = LCD::Get())
336  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_RAND);
337  break;
339  m_shuffleState->DisplayState("intelligent");
340  if (class LCD *lcd = LCD::Get())
341  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_SMART);
342  break;
344  m_shuffleState->DisplayState("album");
345  if (class LCD *lcd = LCD::Get())
346  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_ALBUM);
347  break;
349  m_shuffleState->DisplayState("artist");
350  if (class LCD *lcd = LCD::Get())
351  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_ARTIST);
352  break;
353  default:
355  if (class LCD *lcd = LCD::Get())
356  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_NONE);
357  break;
358  }
359  }
360 
361  if (updateUIList)
362  {
364 
369 
370  // need this to update the next track info
372  if (curMeta)
373  updateTrackInfo(curMeta);
374  }
375 }
376 
378 {
379  // can we switch to this view from the current view?
380  switch (m_currentView)
381  {
382  case MV_PLAYLIST:
383  {
384  if (view != MV_PLAYLISTEDITORTREE && view != MV_PLAYLISTEDITORGALLERY &&
385  view != MV_SEARCH && view != MV_VISUALIZER && view != MV_LYRICS)
386  return;
387  break;
388  }
389 
391  {
392  if (view != MV_PLAYLISTEDITORGALLERY && view != MV_SEARCH && view != MV_VISUALIZER && view != MV_LYRICS)
393  return;
394  break;
395  }
396 
398  {
399  if (view != MV_PLAYLISTEDITORTREE && view != MV_SEARCH && view != MV_VISUALIZER && view != MV_LYRICS)
400  return;
401  break;
402  }
403 
404  case MV_SEARCH:
405  {
406  if (view != MV_VISUALIZER && view != MV_LYRICS)
407  return;
408  break;
409  }
410 
411  case MV_VISUALIZER:
412  {
413  return;
414  }
415 
416  case MV_LYRICS:
417  {
418  if (view != MV_VISUALIZER && view != MV_SEARCH)
419  return;
420  break;
421  }
422 
423  case MV_RADIO:
424  {
425  if (view != MV_VISUALIZER && view != MV_LYRICS)
426  return;
427  break;
428  }
429 
430  default:
431  return;
432  }
433 
435 
436  stopVisualizer();
437 
438  if (m_mainvisual)
439  {
440  delete m_mainvisual;
441  m_mainvisual = nullptr;
442  }
443 
444  gPlayer->removeListener(this);
445  gPlayer->setAllowRestorePos(false);
446 
447  switch (view)
448  {
449  case MV_PLAYLIST:
450  {
451  auto *plview = new PlaylistView(mainStack, this);
452 
453  if (plview->Create())
454  {
455  mainStack->AddScreen(plview);
456  connect(plview, SIGNAL(Exiting()), this, SLOT(viewExited()));
457  }
458  else
459  delete plview;
460 
461  break;
462  }
463 
465  {
466  // if we are switching playlist editor views save and restore
467  // the current position in the tree
468  bool restorePos = (m_currentView == MV_PLAYLISTEDITORGALLERY);
469  auto *oldView = dynamic_cast<PlaylistEditorView *>(this);
470  if (oldView)
471  oldView->saveTreePosition();
472 
473  MythScreenType *parentScreen = (oldView != nullptr ? m_parentScreen : this);
474 
475  auto *pleview = new PlaylistEditorView(mainStack, parentScreen, "tree", restorePos);
476 
477  if (pleview->Create())
478  {
479  mainStack->AddScreen(pleview);
480  connect(pleview, SIGNAL(Exiting()), this, SLOT(viewExited()));
481  }
482  else
483  delete pleview;
484 
485  if (oldView)
486  {
487  disconnect(this , SIGNAL(Exiting()));
488  Close();
489  }
490 
491  break;
492  }
493 
495  {
496  // if we are switching playlist editor views save and restore
497  // the current position in the tree
498  bool restorePos = (m_currentView == MV_PLAYLISTEDITORTREE);
499  auto *oldView = dynamic_cast<PlaylistEditorView *>(this);
500  if (oldView)
501  oldView->saveTreePosition();
502 
503  MythScreenType *parentScreen = (oldView != nullptr ? m_parentScreen : this);
504 
505  auto *pleview = new PlaylistEditorView(mainStack, parentScreen, "gallery", restorePos);
506 
507  if (pleview->Create())
508  {
509  mainStack->AddScreen(pleview);
510  connect(pleview, SIGNAL(Exiting()), this, SLOT(viewExited()));
511  }
512  else
513  delete pleview;
514 
515  if (oldView)
516  {
517  disconnect(this , SIGNAL(Exiting()));
518  Close();
519  }
520 
521  break;
522  }
523 
524  case MV_SEARCH:
525  {
526  auto *sview = new SearchView(mainStack, this);
527 
528  if (sview->Create())
529  {
530  mainStack->AddScreen(sview);
531  connect(sview, SIGNAL(Exiting()), this, SLOT(viewExited()));
532  }
533  else
534  delete sview;
535 
536  break;
537  }
538 
539  case MV_VISUALIZER:
540  {
541  auto *vview = new VisualizerView(mainStack, this);
542 
543  if (vview->Create())
544  {
545  mainStack->AddScreen(vview);
546  connect(vview, SIGNAL(Exiting()), this, SLOT(viewExited()));
547  }
548  else
549  delete vview;
550 
551  break;
552  }
553 
554  case MV_LYRICS:
555  {
556  auto *lview = new LyricsView(mainStack, this);
557 
558  if (lview->Create())
559  {
560  mainStack->AddScreen(lview);
561  connect(lview, SIGNAL(Exiting()), this, SLOT(viewExited()));
562  }
563  else
564  delete lview;
565 
566  break;
567  }
568 
569  default:
570  break;
571  }
572 
574 }
575 
577 {
578  init(false);
579 }
580 
581 bool MusicCommon::keyPressEvent(QKeyEvent *e)
582 {
583  bool handled = false;
584 
585  // if there is a pending jump point pass the key press to the default handler
586  if (GetMythMainWindow()->IsExitingToMain())
587  {
589 
590  // do we need to stop playing?
591  if (gPlayer->isPlaying() && gCoreContext->GetSetting("MusicJumpPointAction", "stop") == "stop")
592  gPlayer->stop(true);
593 
595  }
596 
597  QStringList actions;
598  handled = GetMythMainWindow()->TranslateKeyPress("Music", e, actions, true);
599 
600  for (int i = 0; i < actions.size() && !handled; i++)
601  {
602  QString action = actions[i];
603  handled = true;
604 
605  // if we are currently moving an item,
606  // we only accept UP/DOWN/SELECT/ESCAPE
608  {
610  if (!item)
611  return false;
612 
613  if (action == "SELECT" || action == "ESCAPE")
614  {
615  m_movingTrack = false;
616  item->DisplayState("off", "movestate");
617  }
618  else if (action == "UP")
619  {
621  item->MoveUpDown(true);
628  }
629  else if (action == "DOWN")
630  {
632  item->MoveUpDown(false);
639  }
640 
641  return true;
642  }
643 
644  if (action == "ESCAPE")
645  {
646  // if we was started from another music view screen return to it
647  if (m_parentScreen)
648  {
649  handled = false;
650  }
651  else
652  {
653  // this is the top music view screen so prompt to continue playing
654  QString exit_action = gCoreContext->GetSetting("MusicExitAction", "prompt");
655 
656  if (!gPlayer->isPlaying())
657  {
659  stopAll();
660  Close();
661  }
662  else
663  {
664  if (exit_action == "stop")
665  {
667  stopAll();
668  Close();
669  }
670  else if (exit_action == "play")
671  Close();
672  else
673  showExitMenu();
674  }
675  }
676  }
677  else if (action == "THMBUP")
678  changeRating(true);
679  else if (action == "THMBDOWN")
680  changeRating(false);
681  else if (action == "NEXTTRACK")
682  {
683  if (m_nextButton)
684  m_nextButton->Push();
685  else
686  next();
687  }
688  else if (action == "PREVTRACK")
689  {
690  if (m_prevButton)
691  m_prevButton->Push();
692  else
693  previous();
694  }
695  else if (action == "FFWD")
696  {
698  {
699  if (m_ffButton)
700  m_ffButton->Push();
701  else
702  seekforward();
703  }
704  }
705  else if (action == "RWND")
706  {
708  {
709  if (m_rewButton)
710  m_rewButton->Push();
711  else
712  seekback();
713  }
714  }
715  else if (action == "PAUSE")
716  {
718  {
719  // ignore if we are already playing a radio stream
720  }
721  else if (gPlayer->isPlaying() || (gPlayer->getOutput() && gPlayer->getOutput()->IsPaused()))
722  {
723  // if we are playing or are paused PAUSE will toggle the pause state
724  if (m_pauseButton)
725  m_pauseButton->Push();
726  else
727  pause();
728  }
729  else
730  {
731  // not playing or paused so PAUSE acts the same as PLAY
732  if (m_playButton)
733  m_playButton->Push();
734  else
735  play();
736  }
737  }
738  else if (action == "PLAY")
739  {
740  if (m_playButton)
741  m_playButton->Push();
742  else
743  play();
744  }
745  else if (action == "STOP")
746  {
747  if (m_stopButton)
748  m_stopButton->Push();
749  else
750  stop();
751  m_currentTime = 0;
752  }
753  else if (action == "CYCLEVIS")
754  cycleVisualizer();
755  else if (action == "BLANKSCR")
756  {
757  // change to the blank visualizer
758  if (m_mainvisual)
759  switchVisualizer("Blank");
760 
761  // switch to the full screen visualiser view
764  }
765  else if (action == "VOLUMEDOWN")
766  changeVolume(false);
767  else if (action == "VOLUMEUP")
768  changeVolume(true);
769  else if (action == "SPEEDDOWN")
770  changeSpeed(false);
771  else if (action == "SPEEDUP")
772  changeSpeed(true);
773  else if (action == "MUTE")
774  toggleMute();
775  else if (action == "TOGGLEUPMIX")
776  toggleUpmix();
777  else if (action == "INFO" || action == "EDIT")
778  {
780  {
782  {
783  auto *mdata = m_currentPlaylist->GetItemCurrent()->GetData().value<MusicMetadata*>();
784  if (mdata)
785  {
786  if (action == "INFO")
787  showTrackInfo(mdata);
788  else
789  editTrackInfo(mdata);
790  }
791  }
792  }
793  else
794  {
795  if (action == "INFO")
797  else
799  }
800  }
801  else if (action == "DELETE" && m_currentPlaylist && GetFocusWidget() == m_currentPlaylist)
802  {
804  if (item)
805  {
806  auto *mdata = item->GetData().value<MusicMetadata*>();
807  if (mdata)
808  gPlayer->removeTrack(mdata->ID());
809  }
810  }
811  else if (action == "MENU")
812  ShowMenu();
813  else if (action == "REFRESH")
814  {
815  if (m_currentPlaylist)
817  }
818  else if (action == "MARK")
819  {
820  if (!m_moveTrackMode)
821  {
822  m_moveTrackMode = true;
823  m_movingTrack = false;
824 
827  }
828  else
829  {
830  m_moveTrackMode = false;
831 
833  {
835  if (item)
836  item->DisplayState("off", "movestate");
837 
838  m_movingTrack = false;
839  }
840 
843  }
844  }
845  else if (action == "SWITCHTOPLAYLIST" && m_currentView != MV_PLAYLIST)
847  else if (action == "SWITCHTOPLAYLISTEDITORTREE" && m_currentView != MV_PLAYLISTEDITORTREE)
849  else if (action == "SWITCHTOPLAYLISTEDITORGALLERY" && m_currentView != MV_PLAYLISTEDITORGALLERY)
851  else if (action == "SWITCHTOSEARCH" && m_currentView != MV_SEARCH)
853  else if (action == "SWITCHTOVISUALISER" && m_currentView != MV_VISUALIZER)
855  else if (action == "SWITCHTORADIO" && m_currentView != MV_RADIO)
857  else if (action == "TOGGLESHUFFLE")
858  {
860  updateShuffleMode(true);
861  }
862  else if (action == "TOGGLEREPEAT")
863  {
866  }
867  else
868  handled = false;
869  }
870 
871  if (!handled && MythScreenType::keyPressEvent(e))
872  handled = true;
873  return handled;
874 }
875 
877 {
879  {
880  if (up)
881  gPlayer->incVolume();
882  else
883  gPlayer->decVolume();
884  showVolume();
885  }
886 }
887 
889 {
891  {
892  if (up)
893  gPlayer->incSpeed();
894  else
895  gPlayer->decSpeed();
896  showSpeed(true);
897  }
898 }
899 
901 {
902  if (m_controlVolume)
903  {
904  gPlayer->toggleMute();
905  showVolume();
906  }
907 }
908 
910 {
911  if (gPlayer->getOutput())
913 }
914 
916 {
917  if (!m_trackProgress)
918  return;
919 
921  {
922  // radio mode so show the buffer fill level since we don't know the track length
923  int available = 0;
924  int maxSize = 0;
925  gPlayer->getBufferStatus(&available, &maxSize);
926 
927  if (m_infoText)
928  {
929  QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
930  m_infoText->SetText(status);
931  }
932 
933  if (m_trackProgress)
934  {
935  m_trackProgress->SetTotal(maxSize);
936  m_trackProgress->SetUsed(available);
937  }
938  }
939  else
940  {
941  // show the track played time
942  int percentplayed = 1;
943  if (m_maxTime)
944  percentplayed = (int)(((double)m_currentTime / (double)m_maxTime) * 100);
946  m_trackProgress->SetUsed(percentplayed);
947  }
948 }
949 
951 {
952  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
953 
954  auto *vol = new MythMusicVolumeDialog(popupStack, "volumepopup");
955 
956  if (!vol->Create())
957  {
958  delete vol;
959  return;
960  }
961 
962  popupStack->AddScreen(vol);
963 }
964 
966 {
967  (void) show;
968 }
969 
970 void MusicCommon::switchVisualizer(const QString &visual)
971 {
972  switchVisualizer(m_visualModes.indexOf(visual));
973 }
974 
976 {
977  if (!m_mainvisual)
978  return;
979 
980  if (visual < 0 || visual > m_visualModes.count() - 1)
981  visual = 0;
982 
983  m_currentVisual = visual;
984 
986 
987  if (m_visualText)
989 }
990 
992 {
993  if (!m_mainvisual)
994  return;
995 
996  // Only change the visualizer if there is more than 1 visualizer
997  // and the user currently has a visualizer active
998  if (m_visualModes.count() > 1)
999  {
1000  if (m_randomVisualizer)
1001  {
1002  unsigned int next_visualizer = 0;
1003 
1004  //Find a visual thats not like the previous visual
1005  do
1006  next_visualizer = random() % m_visualModes.count();
1007  while (next_visualizer == m_currentVisual);
1008  m_currentVisual = next_visualizer;
1009  }
1010  else
1011  {
1012  //Change to the next selected visual
1013  m_currentVisual = (m_currentVisual + 1) % m_visualModes.count();
1014  }
1015 
1016  //Change to the new visualizer
1018  }
1019 }
1020 
1022 {
1024  return;
1025 
1027 }
1028 
1030 {
1032  return;
1033 
1035 }
1036 
1038 {
1039  LCD *lcd = LCD::Get();
1040  if (!lcd || !mdata)
1041  return;
1042 
1043  // Set the Artist and Tract on the LCD
1044  lcd->switchToMusic(mdata->Artist(),
1045  mdata->Album(),
1046  mdata->Title());
1047 }
1048 
1050 {
1051  if (LCD *lcd = LCD::Get())
1052  {
1053  lcd->switchToTime();
1054  }
1055 
1056  stopVisualizer();
1057 
1058  gPlayer->stop(true);
1059 }
1060 
1062 {
1063  gPlayer->play();
1064 }
1065 
1067 {
1068  gPlayer->pause();
1069 }
1070 
1072 {
1073  gPlayer->stop();
1074 
1075  QString time_string = getTimeString(m_maxTime, 0);
1076 
1077  if (m_timeText)
1078  m_timeText->SetText(time_string);
1079  if (m_infoText)
1080  m_infoText->Reset();
1081 }
1082 
1084 {
1085  if (m_cycleVisualizer)
1086  cycleVisualizer();
1087 
1088 
1089  gPlayer->next();
1090 }
1091 
1093 {
1094  if (m_cycleVisualizer)
1095  cycleVisualizer();
1096 
1097  gPlayer->previous();
1098 }
1099 
1101 {
1102  int nextTime = m_currentTime + 5;
1103  if (nextTime > m_maxTime)
1104  nextTime = m_maxTime;
1105  seek(nextTime);
1106 }
1107 
1109 {
1110  int nextTime = m_currentTime - 5;
1111  if (nextTime < 0)
1112  nextTime = 0;
1113  seek(nextTime);
1114 }
1115 
1116 void MusicCommon::seek(int pos)
1117 {
1118  if (gPlayer->getOutput())
1119  {
1120  if (gPlayer->getDecoder() && gPlayer->getDecoder()->isRunning())
1121  {
1122  gPlayer->getDecoder()->lock();
1123  gPlayer->getDecoder()->seek(pos);
1124 
1125  if (m_mainvisual)
1126  {
1127  m_mainvisual->mutex()->lock();
1128  m_mainvisual->prepare();
1129  m_mainvisual->mutex()->unlock();
1130  }
1131 
1132  gPlayer->getDecoder()->unlock();
1133  }
1134 
1135  gPlayer->getOutput()->SetTimecode(pos*1000);
1136 
1137  if (!gPlayer->isPlaying())
1138  {
1139  m_currentTime = pos;
1140  if (m_timeText)
1142 
1144 
1145  if (LCD *lcd = LCD::Get())
1146  {
1147  float percent_heard = m_maxTime <= 0 ? 0.0F : ((float)pos /
1148  (float)m_maxTime);
1149 
1150  QString lcd_time_string = getTimeString(pos, m_maxTime);
1151 
1152  // if the string is longer than the LCD width, remove all spaces
1153  if (lcd_time_string.length() > (int)lcd->getLCDWidth())
1154  lcd_time_string.remove(' ');
1155 
1156  lcd->setMusicProgress(lcd_time_string, percent_heard);
1157  }
1158  }
1159  }
1160 }
1161 
1162 void MusicCommon::changeRating(bool increase)
1163 {
1165  return;
1166 
1167  // Rationale here is that if you can't get visual feedback on ratings
1168  // adjustments, you probably should not be changing them
1169  // TODO: should check if the rating is visible in the playlist buttontlist
1170  //if (!m_ratingState)
1171  // return;
1172 
1174  if (!curMeta)
1175  return;
1176 
1177 
1178  if (increase)
1179  curMeta->incRating();
1180  else
1181  curMeta->decRating();
1182 
1183  gPlayer->sendTrackStatsChangedEvent(curMeta->ID());
1184 }
1185 
1186 void MusicCommon::customEvent(QEvent *event)
1187 {
1188  QString statusString;
1189 
1190  if (event->type() == OutputEvent::Playing)
1191  {
1193  if (curMeta)
1194  updateTrackInfo(curMeta);
1195 
1196  statusString = tr("Playing stream.");
1197  if (gPlayer->isPlaying())
1198  {
1199  if (m_stopButton)
1200  m_stopButton->SetLocked(false);
1201  if (m_playButton)
1202  m_playButton->SetLocked(true);
1203  if (m_pauseButton)
1204  m_pauseButton->SetLocked(false);
1205  if (m_trackState)
1206  m_trackState->DisplayState("playing");
1207 
1208  if (m_currentPlaylist)
1209  {
1211  if (item)
1212  {
1213  item->SetFontState("running");
1214  item->DisplayState("playing", "playstate");
1215  }
1216  }
1217 
1218  startVisualizer();
1219 
1220  updateVolume();
1221  }
1222  }
1223  else if (event->type() == OutputEvent::Buffering)
1224  {
1225  statusString = tr("Buffering stream.");
1226  }
1227  else if (event->type() == OutputEvent::Paused)
1228  {
1229  statusString = tr("Stream paused.");
1230 
1231  if (m_stopButton)
1232  m_stopButton->SetLocked(false);
1233  if (m_playButton)
1234  m_playButton->SetLocked(false);
1235  if (m_pauseButton)
1236  m_pauseButton->SetLocked(true);
1237  if (m_trackState)
1238  m_trackState->DisplayState("paused");
1239 
1240  if (m_currentPlaylist)
1241  {
1243  if (item)
1244  {
1245  item->SetFontState("idle");
1246  item->DisplayState("paused", "playstate");
1247  }
1248  }
1249  }
1250  else if (event->type() == OutputEvent::Info)
1251  {
1252 
1253  auto *oe = dynamic_cast<OutputEvent *>(event);
1254 
1255  if (!oe)
1256  return;
1257 
1258  int rs = 0;
1260 
1262  {
1263  if (curMeta)
1264  m_currentTime = rs = curMeta->Length() / 1000;
1265  else
1266  m_currentTime = 0;
1267  }
1268  else
1269  m_currentTime = rs = oe->elapsedSeconds();
1270 
1271  QString time_string = getTimeString(rs, m_maxTime);
1272 
1274 
1275  if (curMeta)
1276  {
1277  if (LCD *lcd = LCD::Get())
1278  {
1279  float percent_heard = m_maxTime <= 0 ?
1280  0.0F:((float)rs / (float)curMeta->Length()) * 1000.0F;
1281 
1282  QString lcd_time_string = time_string;
1283 
1284  // if the string is longer than the LCD width, remove all spaces
1285  if (time_string.length() > (int)lcd->getLCDWidth())
1286  lcd_time_string.remove(' ');
1287 
1288  lcd->setMusicProgress(lcd_time_string, percent_heard);
1289  }
1290  }
1291 
1292  QString info_string;
1293 
1294  // Hack around for cd bitrates
1295  if (oe->bitrate() < 2000)
1296  {
1297 #if QT_VERSION < QT_VERSION_CHECK(5,4,0)
1298  info_string.sprintf(QString("%d "+tr("kbps")+ " %.1f "+ tr("kHz")+ " %s "+ tr("ch")).toUtf8().data(),
1299  static_cast<double>(oe->frequency()) / 1000.0,
1300  oe->channels() > 1 ? "2" : "1");
1301 #else
1302  info_string.sprintf(qUtf8Printable("%d "+tr("kbps")+ " %.1f "+ tr("kHz")+ " %s "+ tr("ch")),
1303  oe->bitrate(), static_cast<double>(oe->frequency()) / 1000.0,
1304  oe->channels() > 1 ? "2" : "1");
1305 #endif
1306  }
1307  else
1308  {
1309 #if QT_VERSION < QT_VERSION_CHECK(5,4,0)
1310  info_string.sprintf(QString("%d "+tr("kbps")+ " %.1f "+ tr("kHz")+ " %s "+ tr("ch")).toUtf8().data(),
1311  static_cast<double>(oe->frequency()) / 1000.0,
1312  oe->channels() > 1 ? "2" : "1");
1313 #else
1314  info_string.sprintf(qUtf8Printable("%.1f "+ tr("kHz")+ " %s "+ tr("ch")),
1315  static_cast<double>(oe->frequency()) / 1000.0,
1316  oe->channels() > 1 ? "2" : "1");
1317 #endif
1318  }
1319 
1320  if (curMeta)
1321  {
1322  if (m_timeText)
1323  m_timeText->SetText(time_string);
1324  if (m_infoText)
1325  m_infoText->SetText(info_string);
1326  }
1327 
1328  // TODO only need to update the playlist times here
1330  }
1331  else if (event->type() == OutputEvent::Stopped)
1332  {
1333  statusString = tr("Stream stopped.");
1334  if (m_stopButton)
1335  m_stopButton->SetLocked(true);
1336  if (m_playButton)
1337  m_playButton->SetLocked(false);
1338  if (m_pauseButton)
1339  m_pauseButton->SetLocked(false);
1340  if (m_trackState)
1341  m_trackState->DisplayState("stopped");
1342 
1343  if (m_currentPlaylist)
1344  {
1346  if (item)
1347  {
1348  item->SetFontState("normal");
1349  item->DisplayState("stopped", "playstate");
1350  }
1351  }
1352 
1353  stopVisualizer();
1354  }
1355  else if (event->type() == DialogCompletionEvent::kEventType)
1356  {
1357  auto dce = dynamic_cast<DialogCompletionEvent*>(event);
1358 
1359  // make sure the user didn't ESCAPE out of the menu
1360  if ((dce == nullptr) || (dce->GetResult() < 0))
1361  return;
1362 
1363  QString resultid = dce->GetId();
1364  QString resulttext = dce->GetResultText();
1365 
1366  if (resultid == "mainmenu")
1367  {
1368  if (resulttext == tr("Fullscreen Visualizer"))
1370  else if (resulttext == tr("Playlist Editor"))
1371  {
1372  if (gCoreContext->GetSetting("MusicPlaylistEditorView", "tree") == "tree")
1374  else
1376  }
1377  else if (resulttext == tr("Search for Music"))
1379  else if (resulttext == tr("Switch To Gallery View"))
1381  else if (resulttext == tr("Switch To Tree View"))
1383  else if (resulttext == tr("Lyrics"))
1385  }
1386  else if (resultid == "submenu")
1387  {
1388  if (resulttext == tr("Search List..."))
1389  searchButtonList();
1390  }
1391  else if (resultid == "playlistmenu")
1392  {
1393  if (resulttext == tr("Sync List With Current Track"))
1394  {
1396  }
1397  else if (resulttext == tr("Remove Selected Track"))
1398  {
1400  if (item)
1401  {
1402  auto *mdata = item->GetData().value<MusicMetadata*>();
1403  if (mdata)
1404  gPlayer->removeTrack(mdata->ID());
1405  }
1406  }
1407  else if (resulttext == tr("Remove All Tracks"))
1408  {
1409  if (gPlayer->getCurrentPlaylist())
1410  {
1412  gPlayer->activePlaylistChanged(-1, true);
1413  }
1414  }
1415  else if (resulttext == tr("Save To New Playlist"))
1416  {
1417  QString message = tr("Enter new playlist name");
1418 
1419  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1420 
1421  auto *inputdialog = new MythTextInputDialog(popupStack, message);
1422 
1423  if (inputdialog->Create())
1424  {
1425  inputdialog->SetReturnEvent(this, "addplaylist");
1426  popupStack->AddScreen(inputdialog);
1427  }
1428  else
1429  delete inputdialog;
1430  }
1431  else if (resulttext == tr("Save To Existing Playlist"))
1432  {
1433  QString message = tr("Select the playlist to save to");
1434  QStringList playlists = gMusicData->m_all_playlists->getPlaylistNames();
1435 
1436  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1437 
1438  auto *searchdialog = new MythUISearchDialog(popupStack, message, playlists);
1439 
1440  if (searchdialog->Create())
1441  {
1442  searchdialog->SetReturnEvent(this, "updateplaylist");
1443  popupStack->AddScreen(searchdialog);
1444  }
1445  }
1446  else if (resulttext == tr("Switch To Move Mode"))
1447  {
1448  m_moveTrackMode = true;
1449  m_movingTrack = false;
1450 
1451  if (m_movingTracksState)
1453  }
1454  else if (resulttext == tr("Switch To Select Mode"))
1455  {
1456  m_moveTrackMode = false;
1457 
1459  {
1461  if (item)
1462  item->DisplayState("off", "movestate");
1463 
1464  m_movingTrack = false;
1465  }
1466 
1467  if (m_movingTracksState)
1469  }
1470  }
1471  else if (resultid == "repeatmenu")
1472  {
1473  int mode = dce->GetData().toInt();
1475  updateRepeatMode();
1476  }
1477  else if (resultid == "shufflemenu")
1478  {
1479  int mode = dce->GetData().toInt();
1481  updateShuffleMode(true);
1482  }
1483  else if (resultid == "exitmenu")
1484  {
1485  if (resulttext == tr("No - Exit, Stop Playing"))
1486  {
1487  gPlayer->savePosition();
1488  stopAll();
1489  Close();
1490  }
1491  else if (resulttext == tr("Yes - Exit, Continue Playing"))
1492  {
1493  Close();
1494  }
1495  }
1496  else if (resultid == "playermenu")
1497  {
1498  if (resulttext == tr("Change Volume"))
1499  showVolume();
1500  else if (resulttext == tr("Mute"))
1501  toggleMute();
1502  else if (resulttext == tr("Previous Track"))
1503  previous();
1504  else if (resulttext == tr("Next Track"))
1505  next();
1506  else if (resulttext == tr("Jump Back"))
1507  seekback();
1508  else if (resulttext == tr("Jump Forward"))
1509  seekforward();
1510  else if (resulttext == tr("Play"))
1511  play();
1512  else if (resulttext == tr("Stop"))
1513  stop();
1514  else if (resulttext == tr("Pause"))
1515  pause();
1516  }
1517  else if (resultid == "quickplaylistmenu")
1518  {
1519  if (resulttext == tr("All Tracks"))
1520  allTracks();
1521  else if (resulttext == tr("From CD"))
1522  fromCD();
1523  else if (resulttext == tr("Tracks By Current Artist"))
1524  byArtist();
1525  else if (resulttext == tr("Tracks From Current Genre"))
1526  byGenre();
1527  else if (resulttext == tr("Tracks From Current Album"))
1528  byAlbum();
1529  else if (resulttext == tr("Tracks From Current Year"))
1530  byYear();
1531  else if (resulttext == tr("Tracks With Same Title"))
1532  byTitle();
1533  }
1534  else if (resultid == "playlistoptionsmenu")
1535  {
1536  if (resulttext == tr("Replace Tracks"))
1537  {
1539  doUpdatePlaylist();
1540  }
1541  else if (resulttext == tr("Add Tracks"))
1542  {
1544  doUpdatePlaylist();
1545  }
1546  }
1547  else if (resultid == "visualizermenu")
1548  {
1549  if (dce->GetResult() >= 0)
1550  {
1551  m_currentVisual = dce->GetData().toInt();
1552 
1553  //Change to the new visualizer
1555  }
1556  }
1557  else if (resultid == "addplaylist")
1558  {
1560  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(resulttext);
1561  gPlayer->playlistChanged(playlist->getID());
1562  }
1563  else if (resultid == "updateplaylist")
1564  {
1565  if (gPlayer->getCurrentPlaylist())
1566  {
1567  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(resulttext);
1568  QString songList = gPlayer->getCurrentPlaylist()->toRawSonglist();
1569  playlist->removeAllTracks();
1570  playlist->fillSongsFromSonglist(songList);
1571  playlist->changed();
1572  gPlayer->playlistChanged(playlist->getID());
1573  }
1574  }
1575  }
1576  else if (event->type() == MusicPlayerEvent::TrackChangeEvent)
1577  {
1578  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1579 
1580  if (!mpe)
1581  return;
1582 
1583  int trackNo = mpe->m_trackID;
1584 
1585  if (m_currentPlaylist)
1586  {
1587  if (m_currentTrack >= 0 && m_currentTrack < m_currentPlaylist->GetCount())
1588  {
1590  if (item)
1591  {
1592  item->SetFontState("normal");
1593  item->DisplayState("default", "playstate");
1594  }
1595  }
1596 
1597  if (trackNo >= 0 && trackNo < m_currentPlaylist->GetCount())
1598  {
1601 
1603  if (item)
1604  {
1605  item->SetFontState("running");
1606  item->DisplayState("playing", "playstate");
1607  }
1608  }
1609  }
1610 
1611  m_currentTrack = trackNo;
1612 
1613  if (gPlayer->getCurrentPlaylist())
1616  if (m_playlistProgress)
1617  {
1620  }
1621 
1624  }
1625  else if (event->type() == MusicPlayerEvent::VolumeChangeEvent)
1626  {
1627  updateVolume();
1628  }
1629  else if (event->type() == MusicPlayerEvent::TrackRemovedEvent)
1630  {
1631  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1632 
1633  if (!mpe)
1634  return;
1635 
1636  int trackID = mpe->m_trackID;
1637 
1638  if (m_currentPlaylist)
1639  {
1640  // find and remove the list item for the removed track
1641  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1642  {
1644  auto *mdata = item->GetData().value<MusicMetadata*>();
1645  if (mdata && mdata->ID() == (MusicMetadata::IdType) trackID)
1646  {
1648  break;
1649  }
1650  }
1651  }
1652 
1654 
1655  // if we have just removed the playing track from the playlist
1656  // move to the next track
1657  if (gPlayer->getCurrentMetadata())
1658  {
1659  if (gPlayer->getCurrentMetadata()->ID() == (MusicMetadata::IdType) trackID)
1660  gPlayer->next();
1661  }
1662 
1663  if (gPlayer->getCurrentPlaylist())
1668 
1671  }
1672  else if (event->type() == MusicPlayerEvent::TrackAddedEvent)
1673  {
1674  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1675 
1676  if (!mpe)
1677  return;
1678 
1679  int trackID = mpe->m_trackID;
1680 
1681  if (m_currentPlaylist)
1682  {
1683  if (trackID == -1)
1684  {
1685  // more than one track has been added so easier to just reload the list
1686  updateUIPlaylist();
1687  }
1688  else
1689  {
1690  // just one track was added so just add that track to the end of the list
1691  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
1692 
1693  if (mdata)
1694  {
1695  InfoMap metadataMap;
1696  mdata->toMap(metadataMap);
1697 
1698  auto *item = new MythUIButtonListItem(m_currentPlaylist, "",
1699  qVariantFromValue(mdata));
1700 
1701  item->SetTextFromMap(metadataMap);
1702 
1704  mdata->ID() == gPlayer->getCurrentMetadata()->ID())
1705  {
1706  item->SetFontState("running");
1707  item->DisplayState("playing", "playstate");
1708  }
1709  else
1710  {
1711  item->SetFontState("normal");
1712  item->DisplayState("default", "playstate");
1713  }
1714 
1715  if (!gPlayer->getCurrentMetadata())
1717  }
1718 
1721  }
1722  }
1723 
1724  if (gPlayer->getCurrentPlaylist())
1727 
1730  }
1731  else if (event->type() == MusicPlayerEvent::AllTracksRemovedEvent)
1732  {
1733  updateUIPlaylist();
1735  updateTrackInfo(nullptr);
1736  }
1737  else if (event->type() == MusicPlayerEvent::MetadataChangedEvent ||
1739  {
1740  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1741 
1742  if (!mpe)
1743  return;
1744 
1745  uint trackID = mpe->m_trackID;
1746 
1747  if (m_currentPlaylist)
1748  {
1749  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1750  {
1752  auto *mdata = item->GetData().value<MusicMetadata*>();
1753 
1754  if (mdata && mdata->ID() == trackID)
1755  {
1756  InfoMap metadataMap;
1757  mdata->toMap(metadataMap);
1758  item->SetTextFromMap(metadataMap);
1759 
1760  item->DisplayState(QString("%1").arg(mdata->Rating()), "ratingstate");
1761  }
1762  }
1763  }
1764 
1765  if (m_playedTracksList)
1766  {
1767  for (int x = 0; x < m_playedTracksList->GetCount(); x++)
1768  {
1770  auto *mdata = item->GetData().value<MusicMetadata*>();
1771 
1772  if (mdata && mdata->ID() == trackID)
1773  {
1774  InfoMap metadataMap;
1775  mdata->toMap(metadataMap);
1776  item->SetTextFromMap(metadataMap);
1777  }
1778  }
1779  }
1780 
1781  if (gPlayer->getCurrentMetadata() && trackID == gPlayer->getCurrentMetadata()->ID())
1783 
1784  // this will ensure the next track info gets updated
1785  if (gPlayer->getNextMetadata() && trackID == gPlayer->getNextMetadata()->ID())
1787  }
1788  else if (event->type() == MusicPlayerEvent::AlbumArtChangedEvent)
1789  {
1790  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1791 
1792  if (!mpe)
1793  return;
1794 
1795  uint trackID = mpe->m_trackID;
1796 
1797  if (m_currentPlaylist)
1798  {
1799  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1800  {
1802  auto *mdata = item->GetData().value<MusicMetadata*>();
1803  if (mdata && mdata->ID() == trackID)
1804  {
1805  // reload the albumart image if one has already been loaded for this track
1806  if (!item->GetImageFilename().isEmpty())
1807  {
1808  QString artFile = mdata->getAlbumArtFile();
1809  if (artFile.isEmpty())
1810  {
1811  item->SetImage("");
1812  item->SetImage("", "coverart");
1813  }
1814  else
1815  {
1816  item->SetImage(mdata->getAlbumArtFile());
1817  item->SetImage(mdata->getAlbumArtFile(), "coverart");
1818  }
1819  }
1820  }
1821  }
1822  }
1823 
1824  if (gPlayer->getCurrentMetadata() && trackID == gPlayer->getCurrentMetadata()->ID())
1826  }
1827  else if (event->type() == MusicPlayerEvent::TrackUnavailableEvent)
1828  {
1829  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1830 
1831  if (!mpe)
1832  return;
1833 
1834  uint trackID = mpe->m_trackID;
1835 
1836  if (m_currentPlaylist)
1837  {
1838  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1839  {
1841  auto *mdata = item->GetData().value<MusicMetadata*>();
1842  if (mdata && mdata->ID() == trackID)
1843  {
1844  item->SetFontState("disabled");
1845  item->DisplayState("unavailable", "playstate");
1846  }
1847  }
1848  }
1849  }
1850 }
1851 
1853 {
1854  if (!m_controlVolume)
1855  {
1856  if (m_volumeText)
1857  m_volumeText->Hide();
1858 
1859  if (m_muteState)
1860  m_muteState->Hide();
1861 
1862  return;
1863  }
1864 
1865  if (m_volumeText)
1866  {
1867  InfoMap map;
1868  gPlayer->toMap(map);
1870  }
1871 
1872  if (m_muteState)
1873  {
1874  bool muted = gPlayer->isMuted();
1875  m_muteState->DisplayState(muted ? "on" : "off");
1876  }
1877 }
1878 
1880 {
1881  if (!mdata)
1882  return;
1883 
1885 
1886  auto *editDialog = new EditMetadataDialog(mainStack, mdata);
1887 
1888  if (!editDialog->Create())
1889  {
1890  delete editDialog;
1891  return;
1892  }
1893 
1894  mainStack->AddScreen(editDialog);
1895 }
1896 
1898 {
1899  if (!mdata)
1900  {
1901  InfoMap metadataMap;
1902  MusicMetadata metadata;
1903  metadata.toMap(metadataMap);
1904  metadata.toMap(metadataMap, "next");
1905  ResetMap(metadataMap);
1906 
1907  if (m_coverartImage)
1909  if (m_ratingState)
1911  if (m_timeText)
1912  m_timeText->Reset();
1913  if (m_infoText)
1914  m_infoText->Reset();
1915  if (m_trackProgress)
1917 
1918  if (m_mainvisual)
1920 
1921  return;
1922  }
1923 
1925  m_maxTime = 0;
1926  else
1927  m_maxTime = mdata->Length() / 1000;
1928 
1929  // get map for current track
1930  InfoMap metadataMap;
1931  mdata->toMap(metadataMap);
1932 
1933  // add the map from the next track
1934  MusicMetadata *nextMetadata = gPlayer->getNextMetadata();
1935  if (nextMetadata)
1936  nextMetadata->toMap(metadataMap, "next");
1937 
1938  // now set text using the map
1939  SetTextFromMap(metadataMap);
1940 
1941  if (m_coverartImage)
1942  {
1943  QString filename = mdata->getAlbumArtFile();
1944  if (!filename.isEmpty())
1945  {
1947  m_coverartImage->Load();
1948  }
1949  else
1951  }
1952 
1953  if (m_ratingState)
1954  m_ratingState->DisplayState(QString("%1").arg(mdata->Rating()));
1955 
1956  setTrackOnLCD(mdata);
1957 }
1958 
1960 {
1961  if (!mdata)
1962  return;
1963 
1964  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1965 
1966  auto *dlg = new TrackInfoDialog(popupStack, mdata, "trackinfopopup");
1967 
1968  if (!dlg->Create())
1969  {
1970  delete dlg;
1971  return;
1972  }
1973 
1974  popupStack->AddScreen(dlg);
1975 }
1976 
1978 {
1979  if (!item)
1980  return;
1981 
1982  if (m_moveTrackMode)
1983  {
1985 
1986  if (m_movingTrack)
1987  item->DisplayState("on", "movestate");
1988  else
1989  item->DisplayState("off", "movestate");
1990  }
1991  else
1993 
1994  if (m_cycleVisualizer)
1995  cycleVisualizer();
1996 }
1997 
1999 {
2000  if (!item)
2001  return;
2002 
2003  auto *mdata = item->GetData().value<MusicMetadata*>();
2004  if (mdata && item->GetText() == " ")
2005  {
2006  if (item->GetImageFilename().isEmpty())
2007  {
2008  QString artFile = mdata->getAlbumArtFile();
2009  if (artFile.isEmpty())
2010  {
2011  item->SetImage("");
2012  item->SetImage("", "coverart");
2013  }
2014  else
2015  {
2016  item->SetImage(mdata->getAlbumArtFile());
2017  item->SetImage(mdata->getAlbumArtFile(), "coverart");
2018  }
2019  }
2020 
2021  InfoMap metadataMap;
2022  mdata->toMap(metadataMap);
2023  item->SetText("");
2024  item->SetTextFromMap(metadataMap);
2025  item->DisplayState(QString("%1").arg(mdata->Rating()), "ratingstate");
2026  }
2027 }
2028 
2030 {
2033 
2034  if (!m_currentPlaylist)
2035  return;
2036 
2038 
2039  m_currentTrack = -1;
2040 
2041  Playlist *playlist = gPlayer->getCurrentPlaylist();
2042 
2043  if (!playlist)
2044  return;
2045 
2046  for (int x = 0; x < playlist->getTrackCount(); x++)
2047  {
2048  MusicMetadata *mdata = playlist->getSongAt(x);
2049  if (mdata)
2050  {
2051  auto *item = new MythUIButtonListItem(m_currentPlaylist, " ",
2052  qVariantFromValue(mdata));
2053 
2054  item->SetText(mdata->Artist() + mdata->Album() + mdata->Title(), "**search**");
2055  item->SetFontState("normal");
2056  item->DisplayState("default", "playstate");
2057 
2058  // if this is the current track update its play state to match the player
2059  if (gPlayer->getCurrentMetadata() && mdata->ID() == gPlayer->getCurrentMetadata()->ID())
2060  {
2061  if (gPlayer->isPlaying())
2062  {
2063  item->SetFontState("running");
2064  item->DisplayState("playing", "playstate");
2065  }
2066  else if (gPlayer->isPaused())
2067  {
2068  item->SetFontState("idle");
2069  item->DisplayState("paused", "playstate");
2070  }
2071  else
2072  {
2073  item->SetFontState("normal");
2074  item->DisplayState("stopped", "playstate");
2075  }
2076 
2079  }
2080  }
2081  }
2082 }
2083 
2085 {
2086  if (!m_playedTracksList)
2087  return;
2088 
2090 
2091  QList<MusicMetadata*> playedList = gPlayer->getPlayedTracksList();
2092 
2093  for (int x = playedList.count(); x > 0; x--)
2094  {
2095  MusicMetadata *mdata = playedList[x-1];
2096  auto *item = new MythUIButtonListItem(m_playedTracksList, "",
2097  qVariantFromValue(mdata));
2098 
2099  InfoMap metadataMap;
2100  mdata->toMap(metadataMap);
2101  item->SetTextFromMap(metadataMap);
2102 
2103  item->SetFontState("normal");
2104  item->DisplayState("default", "playstate");
2105 
2106  item->SetImage(mdata->getAlbumArtFile());
2107  }
2108 }
2109 
2111 {
2112  int trackCount = 0;
2113 
2114  if (gPlayer->getCurrentPlaylist())
2115  trackCount = gPlayer->getCurrentPlaylist()->getTrackCount();
2116 
2117  InfoMap map;
2118  if (gPlayer->isPlaying() && trackCount > 0)
2119  {
2120  QString playlistcurrent = QLocale::system().toString(m_currentTrack + 1);
2121  QString playlisttotal = QLocale::system().toString(trackCount);
2122 
2123  map["playlistposition"] = tr("%1 of %2").arg(playlistcurrent)
2124  .arg(playlisttotal);
2125  map["playlistcurrent"] = playlistcurrent;
2126  map["playlistcount"] = playlisttotal;
2128  map["playlistplayedtime"] = getTimeString(m_playlistPlayedTime + m_currentTime, 0);
2129  map["playlisttotaltime"] = getTimeString(m_playlistMaxTime, 0);
2130  QString playlistName = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->getName() : "";
2131  if (playlistName == "default_playlist_storage")
2132  playlistName = tr("Default Playlist");
2133  else if (playlistName == "stream_playlist")
2134  playlistName = tr("Stream Playlist");
2135  map["playlistname"] = playlistName;
2136  }
2137  else
2138  {
2139  map["playlistposition"] = "";
2140  map["playlistcurrent"] = "";
2141  map["playlistcount"] = "";
2142  map["playlisttime"] = "";
2143  map["playlistplayedtime"] = "";
2144  map["playlisttotaltime"] = "";
2145  map["playlistname"] = "";
2146  }
2147 
2148  SetTextFromMap(map);
2149 
2150  if (m_playlistProgress)
2152 }
2153 
2154 QString MusicCommon::getTimeString(int exTime, int maxTime)
2155 {
2156  QString time_string;
2157 
2158  int eh = exTime / 3600;
2159  int em = (exTime / 60) % 60;
2160  int es = exTime % 60;
2161 
2162  int maxh = maxTime / 3600;
2163  int maxm = (maxTime / 60) % 60;
2164  int maxs = maxTime % 60;
2165 
2166  if (maxTime <= 0)
2167  {
2168  if (eh > 0)
2169  time_string.sprintf("%d:%02d:%02d", eh, em, es);
2170  else
2171  time_string.sprintf("%02d:%02d", em, es);
2172  }
2173  else
2174  {
2175  if (maxh > 0)
2176  time_string.sprintf("%d:%02d:%02d / %02d:%02d:%02d", eh, em,
2177  es, maxh, maxm, maxs);
2178  else
2179  time_string.sprintf("%02d:%02d / %02d:%02d", em, es, maxm,
2180  maxs);
2181  }
2182 
2183  return time_string;
2184 }
2185 
2187 {
2188  auto *buttonList = dynamic_cast<MythUIButtonList *>(GetFocusWidget());
2189  if (buttonList)
2190  buttonList->ShowSearchDialog();
2191 
2192  auto *buttonTree = dynamic_cast<MythUIButtonTree *>(GetFocusWidget());
2193  if (buttonTree)
2194  buttonTree->ShowSearchDialog();
2195 }
2196 
2198 {
2199  MythMenu *mainMenu = createMainMenu();
2200 
2201  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2202 
2203  auto *menuPopup = new MythDialogBox(mainMenu, popupStack, "actionmenu");
2204 
2205  if (menuPopup->Create())
2206  popupStack->AddScreen(menuPopup);
2207  else
2208  delete mainMenu;
2209 }
2210 
2212 {
2213  QString label = tr("View Actions");
2214 
2215  auto *menu = new MythMenu(label, this, "mainmenu");
2216 
2218  menu->AddItem(tr("Switch To Gallery View"));
2220  menu->AddItem(tr("Switch To Tree View"));
2221  else if (m_currentView == MV_PLAYLIST)
2222  menu->AddItem(MusicCommon::tr("Playlist Editor"));
2223 
2224  QStringList screenList;
2225  MythScreenType *screen = this;
2226  while (screen)
2227  {
2228  screenList.append(screen->objectName());
2229  screen = dynamic_cast<MusicCommon*>(screen)->m_parentScreen;
2230  }
2231 
2232  if (!screenList.contains("searchview") && !screenList.contains("streamview"))
2233  menu->AddItem(tr("Search for Music"));
2234 
2235  if (!screenList.contains("visualizerview"))
2236  menu->AddItem(tr("Fullscreen Visualizer"));
2237 
2238  if (!screenList.contains("lyricsview"))
2239  menu->AddItem(tr("Lyrics"));
2240 
2241  menu->AddItem(tr("More Options"), nullptr, createSubMenu());
2242 
2243  return menu;
2244 }
2245 
2247 {
2248  QString label = tr("Actions");
2249 
2250  auto *menu = new MythMenu(label, this, "submenu");
2251 
2252  if (GetFocusWidget() && (GetFocusWidget()->inherits("MythUIButtonList") ||
2253  GetFocusWidget()->inherits("MythUIButtonTree")))
2254  menu->AddItem(tr("Search List..."));
2255 
2257  {
2258  menu->AddItem(tr("Playlist Options"), nullptr, createPlaylistMenu());
2259  menu->AddItem(tr("Set Shuffle Mode"), nullptr, createShuffleMenu());
2260  menu->AddItem(tr("Set Repeat Mode"), nullptr, createRepeatMenu());
2261  }
2262 
2263  menu->AddItem(tr("Player Options"), nullptr, createPlayerMenu());
2264 
2266  menu->AddItem(tr("Quick Playlists"), nullptr, createQuickPlaylistsMenu());
2267 
2268  if (m_visualizerVideo)
2269  menu->AddItem(tr("Change Visualizer"), nullptr, createVisualizerMenu());
2270 
2271  return menu;
2272 }
2273 
2275 {
2276  QString label = tr("Playlist Options");
2277 
2278  auto *menu = new MythMenu(label, this, "playlistmenu");
2279 
2280  if (m_currentPlaylist)
2281  {
2282  menu->AddItem(tr("Sync List With Current Track"));
2283  menu->AddItem(tr("Remove Selected Track"));
2284  }
2285 
2286  menu->AddItem(tr("Remove All Tracks"));
2287 
2288  if (m_currentPlaylist)
2289  {
2290  menu->AddItem(tr("Save To New Playlist"));
2291  menu->AddItem(tr("Save To Existing Playlist"));
2292 
2293  if (m_moveTrackMode)
2294  menu->AddItem(tr("Switch To Select Mode"));
2295  else
2296  menu->AddItem(tr("Switch To Move Mode"));
2297  }
2298 
2299  return menu;
2300 }
2301 
2303 {
2304  QString label = tr("Exiting Music Player.\n\n"
2305  "Do you want to continue playing in the background?");
2306 
2307  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2308 
2309  auto *menu = new MythDialogBox(label, popupStack, "exitmenu");
2310 
2311  if (!menu->Create())
2312  {
2313  delete menu;
2314  return;
2315  }
2316 
2317  menu->SetReturnEvent(this, "exitmenu");
2318 
2319  menu->AddButton(tr("No - Exit, Stop Playing"));
2320  menu->AddButton(tr("Yes - Exit, Continue Playing"));
2321  menu->AddButton(tr("Cancel"));
2322 
2323  popupStack->AddScreen(menu);
2324 }
2325 
2327 {
2328  QString label = tr("Player Actions");
2329 
2330  auto *menu = new MythMenu(label, this, "playermenu");
2331 
2332  menu->AddItem(tr("Change Volume"));
2333  menu->AddItem(tr("Mute"));
2334  menu->AddItem(tr("Previous Track"));
2335  menu->AddItem(tr("Next Track"));
2336 
2338  {
2339  menu->AddItem(tr("Jump Back"));
2340  menu->AddItem(tr("Jump Forward"));
2341  }
2342 
2343  menu->AddItem(tr("Play"));
2344  menu->AddItem(tr("Stop"));
2345 
2347  menu->AddItem(tr("Pause"));
2348 
2349  return menu;
2350 }
2351 
2353 {
2354  QString label = tr("Set Repeat Mode");
2355 
2356  auto *menu = new MythMenu(label, this, "repeatmenu");
2357 
2358  menu->AddItem(tr("None"), qVariantFromValue((int)MusicPlayer::REPEAT_OFF));
2359  menu->AddItem(tr("Track"), qVariantFromValue((int)MusicPlayer::REPEAT_TRACK));
2360  menu->AddItem(tr("All"), qVariantFromValue((int)MusicPlayer::REPEAT_ALL));
2361 
2362  menu->SetSelectedByData(static_cast<int>(gPlayer->getRepeatMode()));
2363 
2364  return menu;
2365 }
2366 
2368 {
2369  QString label = tr("Set Shuffle Mode");
2370 
2371  auto *menu = new MythMenu(label, this, "shufflemenu");
2372 
2373  menu->AddItem(tr("None"), qVariantFromValue((int)MusicPlayer::SHUFFLE_OFF));
2374  menu->AddItem(tr("Random"), qVariantFromValue((int)MusicPlayer::SHUFFLE_RANDOM));
2375  menu->AddItem(tr("Smart"), qVariantFromValue((int)MusicPlayer::SHUFFLE_INTELLIGENT));
2376  menu->AddItem(tr("Album"), qVariantFromValue((int)MusicPlayer::SHUFFLE_ALBUM));
2377  menu->AddItem(tr("Artist"), qVariantFromValue((int)MusicPlayer::SHUFFLE_ARTIST));
2378 
2379  menu->SetSelectedByData(static_cast<int>(gPlayer->getShuffleMode()));
2380 
2381  return menu;
2382 }
2383 
2385 {
2386  QString label = tr("Quick Playlists");
2387 
2388  auto *menu = new MythMenu(label, this, "quickplaylistmenu");
2389 
2390  menu->AddItem(tr("All Tracks"));
2391 
2393  menu->AddItem(tr("From CD"));
2394 
2395  if (gPlayer->getCurrentMetadata())
2396  {
2397  menu->AddItem(tr("Tracks By Current Artist"));
2398  menu->AddItem(tr("Tracks From Current Album"));
2399  menu->AddItem(tr("Tracks From Current Genre"));
2400  menu->AddItem(tr("Tracks From Current Year"));
2401  menu->AddItem(tr("Tracks With Same Title"));
2402  }
2403 
2404  return menu;
2405 }
2406 
2408 {
2409  QString label = tr("Choose Visualizer");
2410 
2411  auto *menu = new MythMenu(label, this, "visualizermenu");
2412 
2413  for (uint x = 0; x < static_cast<uint>(m_visualModes.count()); x++)
2414  menu->AddItem(m_visualModes.at(x), qVariantFromValue(x));
2415 
2416  menu->SetSelectedByData(m_currentVisual);
2417 
2418  return menu;
2419 }
2420 
2422 {
2423  QString label = tr("Add to Playlist Options");
2424 
2425  auto *menu = new MythMenu(label, this, "playlistoptionsmenu");
2426 
2427  menu->AddItem(tr("Replace Tracks"));
2428  menu->AddItem(tr("Add Tracks"));
2429 
2430  return menu;
2431 }
2432 
2434 {
2435  m_whereClause = "ORDER BY music_artists.artist_name, album_name, disc_number, track";
2437 }
2438 
2440 {
2441  m_whereClause = "";
2442  m_songList.clear();
2443 
2444  // get the list of cd tracks
2445  for (int x = 1; x <= gMusicData->m_all_music->getCDTrackCount(); x++)
2446  {
2448  if (mdata)
2449  {
2450  m_songList.append((mdata)->ID());
2451  }
2452  }
2453 
2455 }
2456 
2458 {
2460  if (!mdata)
2461  return;
2462 
2463  QString value = formattedFieldValue(mdata->Artist().toUtf8().constData());
2464  m_whereClause = "WHERE music_artists.artist_name = " + value +
2465  " ORDER BY album_name, disc_number, track";
2466 
2468 }
2469 
2471 {
2473  if (!mdata)
2474  return;
2475 
2476  QString value = formattedFieldValue(mdata->Album().toUtf8().constData());
2477  m_whereClause = "WHERE album_name = " + value +
2478  " ORDER BY disc_number, track";
2479 
2481 }
2482 
2484 {
2486  if (!mdata)
2487  return;
2488 
2489  QString value = formattedFieldValue(mdata->Genre().toUtf8().constData());
2490  m_whereClause = "WHERE genre = " + value +
2491  " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2492 
2494 }
2495 
2497 {
2499  if (!mdata)
2500  return;
2501 
2502  QString value = formattedFieldValue(mdata->Year());
2503  m_whereClause = "WHERE music_songs.year = " + value +
2504  " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2505 
2507 }
2508 
2510 {
2512  if (!mdata)
2513  return;
2514 
2515  QString value = formattedFieldValue(mdata->Title().toUtf8().constData());
2516  m_whereClause = "WHERE music_songs.name = " + value +
2517  " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2518 
2520 }
2521 
2523 {
2524  if (!gPlayer->getCurrentPlaylist())
2525  return;
2526 
2528 
2529  // Don't bother showing the dialog if the current playlist is empty
2530  if (gPlayer->getCurrentPlaylist()->getTrackCount() == 0)
2531  {
2533  doUpdatePlaylist();
2534  return;
2535  }
2536 
2538 
2539  if (addMainMenu)
2540  menu->AddItem(tr("More Options"), nullptr, createMainMenu());
2541 
2542  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2543 
2544  auto *menuPopup = new MythDialogBox(menu, popupStack, "playlistoptionsmenu");
2545 
2546  if (menuPopup->Create())
2547  popupStack->AddScreen(menuPopup);
2548  else
2549  delete menu;
2550 }
2551 
2553 {
2554  int curTrackID = -1;
2555  int trackCount = 0;
2556  int curPos = gPlayer->getCurrentTrackPos();
2557 
2558  if (gPlayer->getCurrentPlaylist())
2559  trackCount = gPlayer->getCurrentPlaylist()->getTrackCount();
2560 
2561  // store id of current track
2562  if (gPlayer->getCurrentMetadata())
2563  curTrackID = gPlayer->getCurrentMetadata()->ID();
2564 
2565  if (!m_whereClause.isEmpty())
2566  {
2567  // update playlist from quick playlist
2569  m_whereClause, true,
2570  m_playlistOptions.insertPLOption, curTrackID);
2571  m_whereClause.clear();
2572  }
2573  else if (!m_songList.isEmpty())
2574  {
2575  // update playlist from song list (from the playlist editor)
2577  m_songList, true,
2578  m_playlistOptions.insertPLOption, curTrackID);
2579 
2580  m_songList.clear();
2581  }
2582 
2584 
2585  updateUIPlaylist();
2586 
2587  if (m_currentTrack == -1)
2588  playFirstTrack();
2589  else
2590  {
2592  {
2593  case PL_CURRENT:
2594  {
2595  if (!restorePosition(curTrackID))
2596  playFirstTrack();
2597 
2598  break;
2599  }
2600 
2601  case PL_FIRST:
2602  playFirstTrack();
2603  break;
2604 
2605  case PL_FIRSTNEW:
2606  {
2608  {
2609  case PL_REPLACE:
2610  playFirstTrack();
2611  break;
2612 
2613  case PL_INSERTATEND:
2614  {
2615  pause();
2616  if (!gPlayer->setCurrentTrackPos(trackCount))
2617  playFirstTrack();
2618  break;
2619  }
2620 
2621  case PL_INSERTAFTERCURRENT:
2622  if (!gPlayer->setCurrentTrackPos(curPos + 1))
2623  playFirstTrack();
2624  break;
2625 
2626  default:
2627  playFirstTrack();
2628  }
2629 
2630  break;
2631  }
2632  }
2633  }
2634 
2635  if (gPlayer->getCurrentPlaylist())
2640 }
2641 
2643 {
2644  // try to move to the current track
2645  bool foundTrack = false;
2646 
2647  if (trackID != -1 && gPlayer->getCurrentPlaylist())
2648  {
2649  for (int x = 0; x < gPlayer->getCurrentPlaylist()->getTrackCount(); x++)
2650  {
2652  if (mdata && mdata->ID() == (MusicMetadata::IdType) trackID)
2653  {
2654  m_currentTrack = x;
2655  if (m_currentPlaylist)
2656  {
2659  if (item)
2660  {
2661  item->SetFontState("running");
2662  item->DisplayState("playing", "playstate");
2663  }
2664  }
2665 
2666  foundTrack = true;
2667 
2668  break;
2669  }
2670  }
2671  }
2672 
2673  return foundTrack;
2674 }
2675 
2677 {
2679 }
2680 
2681 //---------------------------------------------------------
2682 // MythMusicVolumeDialog
2683 //---------------------------------------------------------
2684 #define MUSICVOLUMEPOPUPTIME (4 * 1000)
2685 
2687 {
2688  if (m_displayTimer)
2689  {
2690  m_displayTimer->stop();
2691  delete m_displayTimer;
2692  m_displayTimer = nullptr;
2693  }
2694 }
2695 
2697 {
2698  if (!LoadWindowFromXML("music-ui.xml", "volume_popup", this))
2699  return false;
2700 
2701  UIUtilW::Assign(this, m_volText, "volume");
2702  UIUtilW::Assign(this, m_volProgress, "volumeprogress");
2703  UIUtilW::Assign(this, m_muteState, "mutestate");
2704 
2705  if (m_volProgress)
2706  m_volProgress->SetTotal(100);
2707 
2708  updateDisplay();
2709 
2710  m_displayTimer = new QTimer(this);
2711  connect(m_displayTimer, SIGNAL(timeout()), this, SLOT(Close()));
2712  m_displayTimer->setSingleShot(true);
2714 
2715  return true;
2716 }
2717 
2719 {
2720  QStringList actions;
2721  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);
2722 
2723  for (int i = 0; i < actions.size() && !handled; i++)
2724  {
2725  QString action = actions[i];
2726  handled = true;
2727 
2728  if (action == "UP" || action == "VOLUMEUP")
2729  increaseVolume();
2730  else if (action == "DOWN" || action == "VOLUMEDOWN")
2731  decreaseVolume();
2732  else if (action == "MUTE" || action == "SELECT")
2733  toggleMute();
2734  else
2735  handled = false;
2736  }
2737 
2738  if (!handled && MythScreenType::keyPressEvent(event))
2739  handled = true;
2740 
2741  // Restart the display timer only if we handled this keypress, if nothing
2742  // has changed there's no need to keep the volume on-screen
2743  if (handled)
2745 
2746  return handled;
2747 }
2748 
2750 {
2751  gPlayer->incVolume();
2752  updateDisplay();
2753 }
2754 
2756 {
2757  gPlayer->decVolume();
2758  updateDisplay();
2759 }
2760 
2762 {
2763  gPlayer->toggleMute();
2764  updateDisplay();
2765 }
2766 
2768 {
2769  if (m_muteState)
2770  m_muteState->DisplayState(gPlayer->isMuted() ? "on" : "off");
2771 
2772  if (m_volProgress)
2774 
2775  if (m_volText)
2776  {
2777  InfoMap map;
2778  gPlayer->toMap(map);
2779  m_volText->SetTextFromMap(map);
2780  }
2781 }
2782 
2783 //---------------------------------------------------------
2784 // TrackInfoDialog
2785 //---------------------------------------------------------
2787 {
2788  if (!LoadWindowFromXML("music-ui.xml", "trackdetail_popup", this))
2789  return false;
2790 
2791  InfoMap metadataMap;
2792  m_metadata->toMap(metadataMap);
2793  SetTextFromMap(metadataMap);
2794 
2795  MythUIStateType *ratingState = dynamic_cast<MythUIStateType *>(GetChild("rating_state"));
2796  if (ratingState)
2797  ratingState->DisplayState(QString("%1").arg(m_metadata->Rating()));
2798 
2799  MythUIImage *albumImage = dynamic_cast<MythUIImage *>(GetChild("coverart"));
2800  if (albumImage)
2801  {
2802  if (!m_metadata->getAlbumArtFile().isEmpty())
2803  {
2804  albumImage->SetFilename(m_metadata->getAlbumArtFile());
2805  albumImage->Load();
2806  }
2807  }
2808 
2809  // hide the song ID by default
2810  MythUIText *songID = dynamic_cast<MythUIText *>(GetChild("songid"));
2811  if (songID)
2812  songID->Hide();
2813 
2814  return true;
2815 }
2816 
2817 bool TrackInfoDialog::keyPressEvent(QKeyEvent *event)
2818 {
2819  QStringList actions;
2820  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);
2821 
2822  for (int i = 0; i < actions.size() && !handled; i++)
2823  {
2824  QString action = actions[i];
2825  handled = true;
2826 
2827  if (action == "INFO")
2828  Close();
2829  if (action == "0")
2830  {
2831  // if it's available show the song ID
2832  MythUIText *songID = dynamic_cast<MythUIText *>(GetChild("songid"));
2833  if (songID)
2834  songID->Show();
2835  }
2836  else
2837  handled = false;
2838  }
2839 
2840  if (!handled && MythScreenType::keyPressEvent(event))
2841  handled = true;
2842 
2843  return handled;
2844 }
This widget is used for grouping other widgets for display when a particular named state is called.
static Type Info
Definition: output.h:63
virtual bool IsPaused(void) const =0
void decVolume(void)
MythUIButton * m_playButton
Definition: musiccommon.h:196
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1090
QString m_whereClause
Definition: musiccommon.h:165
void setPlayMode(PlayMode mode)
int getCDTrackCount(void) const
void seek(int)
bool Create(void) override
void Show(void)
void toggleMute(void)
void byArtist(void)
void setShuffleMode(ShuffleMode mode)
void changeCurrentTrack(int trackNo)
change the current track to the given track
static void startPlayback(void)
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
uint getVolume(void) const
static void changeSpeed(bool up)
static Type MetadataChangedEvent
Definition: musicplayer.h:46
void sendTrackStatsChangedEvent(int trackID)
void doUpdatePlaylist(void)
virtual bool ToggleUpmix(void)
Definition: audiooutput.h:155
void switchVisualizer(const QString &visual)
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
void cycleVisualizer(void)
QStringList getPlaylistNames(void)
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
void copyNewPlaylist(const QString &name)
Playlist * getCurrentPlaylist(void)
MythUIProgressBar * m_volProgress
Definition: musiccommon.h:231
MythMenu * createQuickPlaylistsMenu(void)
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
void seekback(void)
RepeatMode toggleRepeatMode(void)
void removeListener(QObject *listener)
MythUIButton * m_prevButton
Definition: musiccommon.h:193
MythUIText * m_trackSpeedText
Definition: musiccommon.h:185
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
void removeVisual(MainVisual *visual)
static Type TrackAddedEvent
Definition: musicplayer.h:42
static Type Playing
Definition: output.h:61
virtual void SetTimecode(int64_t timecode)=0
static void editTrackInfo(MusicMetadata *mdata)
MythUIText * m_volumeText
Definition: musiccommon.h:189
MusicView m_currentView
Definition: musiccommon.h:139
bool isStopped(void)
Definition: musicplayer.h:104
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
virtual void unlock(void)
Definition: decoder.h:81
uint32_t IdType
Definition: musicmetadata.h:84
void stopAll(void)
QString Genre() const
MythUIText * m_trackProgressText
Definition: musiccommon.h:184
Basic menu dialog, message and a list of options.
MusicCommon(MythScreenStack *parent, MythScreenType *parentScreen, const QString &name)
Definition: musiccommon.cpp:48
void showPlaylistOptionsMenu(bool addMainMenu=false)
PlayPLOption playPLOption
Definition: playlist.h:37
QString GetImageFilename(const QString &name="") const
PlaylistOptions m_playlistOptions
Definition: musiccommon.h:164
void customEvent(QEvent *event) override
Playlist * getActive(void)
bool setCurrentTrackPos(int pos)
void SetTextFromMap(const InfoMap &map)
Definition: mythuitext.cpp:158
void ShowMenu(void) override
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
bool m_fullscreenBlank
Definition: musiccommon.h:143
bool isPlaying(void)
Definition: musicplayer.h:102
static void showVolume(void)
MythUIStateType * m_repeatState
Definition: musiccommon.h:177
int Length() const
MythScreenStack * GetStack(const QString &stackname)
void incVolume(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void addVisual(MainVisual *visual)
MythUIVideo * m_visualizerVideo
Definition: musiccommon.h:206
MythScreenStack * GetMainStack()
MythUIText * m_noTracksText
Definition: musiccommon.h:174
bool Create(void) override
void updateProgressBar(void)
MythUIButtonListItem * GetItemAt(int pos) const
static MythThemedMenu * menu
MythUIButton * m_nextButton
Definition: musiccommon.h:199
QString getName(void)
Definition: playlist.h:103
uint m_playlistMaxTime
Definition: musiccommon.h:161
MythUIStateType * m_ratingState
Definition: musiccommon.h:181
MythUIProgressBar * m_trackProgress
Definition: musiccommon.h:183
RepeatMode getRepeatMode(void)
Definition: musicplayer.h:180
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
QStringList getVisualizations(void)
Definition: mainvisual.h:56
MythMenu * createVisualizerMenu(void)
void RemoveItem(MythUIButtonListItem *item)
MythUIText * m_volText
Definition: musiccommon.h:229
MythUIStateType * m_muteState
Definition: musiccommon.h:188
static Type Buffering
Definition: output.h:62
int Rating() const
Playlist * getPlaylist(int id)
static Type kEventType
Definition: mythdialogbox.h:50
static void setTrackOnLCD(MusicMetadata *mdata)
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
bool m_moveTrackMode
Definition: musiccommon.h:150
void updatePlaylistStats(void)
void changeVolume(bool up)
void byTitle(void)
static LCD * Get(void)
Definition: lcddevice.cpp:65
virtual void lock(void)
Definition: decoder.h:80
#define MUSICVOLUMEPOPUPTIME
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:203
static Type TrackChangeEvent
Definition: musicplayer.h:40
void Hide(void)
virtual void Close()
QString Artist() const
MythUIButton * m_stopButton
Definition: musiccommon.h:197
void playlistItemClicked(MythUIButtonListItem *item)
void savePosition(void)
void updateVolume(void)
void fromCD(void)
virtual void SetVisible(bool visible)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void previous(void)
PlaylistContainer * m_all_playlists
Definition: musicdata.h:53
void previous(void)
void updateShuffleMode(bool updateUIList=false)
static QString getTimeString(int exTime, int maxTime)
QString toRawSonglist(bool shuffled=false, bool tracksOnly=false)
Definition: playlist.cpp:863
MusicView
Definition: musiccommon.h:30
void next(void)
MythMenu * createShuffleMenu(void)
MusicMetadata * getMetadata(int an_id)
static void show(uint8_t *buf, int length)
Definition: ringbuffer.c:316
unsigned int m_currentVisual
Definition: musiccommon.h:148
void updateRepeatMode(void)
PlayMode getPlayMode(void)
Definition: musicplayer.h:70
void showExitMenu(void)
void SetLocked(bool locked)
void next(void)
MythUIButtonList * m_playedTracksList
Definition: musiccommon.h:204
void stop(void)
MainVisual * m_mainvisual
Definition: musiccommon.h:142
~MusicCommon(void)
Definition: musiccommon.cpp:63
int getTrackCount(void)
Definition: playlist.h:79
void byAlbum(void)
static void play(void)
uint m_playlistTrackCount
Definition: musiccommon.h:159
void updateTrackInfo(MusicMetadata *mdata)
QString GetSetting(const QString &key, const QString &defaultval="")
IdType ID() const
MythMenu * createMainMenu(void)
void fillSonglistFromQuery(const QString &whereClause, bool removeDuplicates=false, InsertPLOption insertOption=PL_REPLACE, int currentTrackID=0)
Definition: playlist.cpp:696
QList< MusicMetadata * > & getPlayedTracksList(void)
Definition: musicplayer.h:130
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:83
MythUIButton * m_rewButton
Definition: musiccommon.h:194
bool isRunning(void) const
Definition: mthread.cpp:274
void getBufferStatus(int *bufferAvailable, int *bufferSize)
MythUIButton * m_pauseButton
Definition: musiccommon.h:195
MythUIText * m_timeText
Definition: musiccommon.h:171
bool isMuted(void) const
Definition: musicplayer.h:82
QString getAlbumArtFile(void)
void Reset(void) override
Reset the image back to the default defined in the theme.
void changed(void)
Definition: playlist.cpp:992
virtual void SetTextFromMap(const InfoMap &infoMap)
static Type TrackRemovedEvent
Definition: musicplayer.h:43
bool m_movingTrack
Definition: musiccommon.h:151
static Type TrackUnavailableEvent
Definition: musicplayer.h:44
MythScreenType * m_parentScreen
Definition: musiccommon.h:138
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
void pause(void)
MythUIText * m_visualText
Definition: musiccommon.h:173
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MusicMetadata * m_metadata
Definition: musiccommon.h:247
bool Create(void) override
void SetText(const QString &text, const QString &name="", const QString &state="")
unsigned int uint
Definition: compat.h:140
QString Album() const
int getID(void)
Definition: playlist.h:108
void searchButtonList(void)
ShuffleMode toggleShuffleMode(void)
bool m_cycleVisualizer
Definition: musiccommon.h:144
bool MoveUpDown(bool flag)
void viewExited(void)
void updateUIPlaylist(void)
void byGenre(void)
virtual void seek(double)=0
void stop(bool stopAll=false)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
static void showSpeed(bool show)
MythUIType * GetFocusWidget(void) const
MythUIStateType * m_trackState
Definition: musiccommon.h:186
int m_currentTime
Definition: musiccommon.h:156
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
MythMainWindow * GetMythMainWindow(void)
void startVisualizer(void)
QString GetText(const QString &name="") const
MythUIImage * m_coverartImage
Definition: musiccommon.h:201
void setAllowRestorePos(bool allow)
Definition: musicplayer.h:143
int getCurrentVisual(void)
Definition: mainvisual.h:58
void play(void)
MythUIStateType * m_muteState
Definition: musiccommon.h:230
void restorePosition(void)
MythMenu * createRepeatMenu(void)
Dialog prompting the user to enter a text string.
void byYear(void)
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
int Year() const
bool m_randomVisualizer
Definition: musiccommon.h:145
ShuffleMode getShuffleMode(void)
Definition: musicplayer.h:184
static Type AllTracksRemovedEvent
Definition: musicplayer.h:45
uint m_playlistPlayedTime
Definition: musiccommon.h:160
static void playlistItemVisible(MythUIButtonListItem *item)
void addListener(QObject *listener)
MythMenu * createPlayerMenu(void)
static void changeRating(bool increase)
QStringList m_visualModes
Definition: musiccommon.h:147
MythUIProgressBar * m_playlistProgress
Definition: musiccommon.h:191
bool GetBoolSetting(const QString &key, bool defaultval=false)
QMutex * mutex()
Definition: visual.h:25
void prepare(void) override
Definition: mainvisual.cpp:139
int getCurrentTrackPos(void)
Definition: musicplayer.h:132
MythUIStateType * m_shuffleState
Definition: musiccommon.h:176
QString Title() const
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
bool isPaused(void)
Definition: musicplayer.h:103
void fillSongsFromSonglist(const QString &songList)
Definition: playlist.cpp:650
void updateUIPlayedList(void)
void init(bool startPlayback=true)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIText * m_infoText
Definition: musiccommon.h:172
static void pause(void)
void SetLockable(bool lockable)
Definition: mythuibutton.h:39
void SetFontState(const QString &state, const QString &name="")
void getStats(uint *trackCount, uint *totalLength, uint currentTrack=0, uint *playedLength=nullptr) const
Definition: playlist.cpp:510
void stopVisualizer(void)
bool DisplayState(const QString &name)
MusicData * gMusicData
Definition: musicdata.cpp:20
void toMap(InfoMap &infoMap)
MusicMetadata * getCDMetadata(int m_the_track)
Definition: lcddevice.h:165
bool m_controlVolume
Definition: musiccommon.h:153
MythMenu * createSubMenu(void)
InsertPLOption insertPLOption
Definition: playlist.h:36
QList< int > m_songList
Definition: musiccommon.h:168
void allTracks(void)
void SetItemCurrent(MythUIButtonListItem *item)
QString formattedFieldValue(const QVariant &value)
void playlistChanged(int playlistID)
void removeTrack(int trackID)
void moveTrackUpDown(bool moveUp, int whichTrack)
static long int random(void)
Definition: compat.h:149
void fillSonglistFromList(const QList< int > &songList, bool removeDuplicates, InsertPLOption insertOption, int currentTrackID)
Definition: playlist.cpp:793
void toggleMute(void)
MythUIStateType * m_movingTracksState
Definition: musiccommon.h:179
Decoder * getDecoder(void)
Definition: musicplayer.h:115
bool restorePosition(int trackID)
AudioOutput * getOutput(void)
Definition: musicplayer.h:117
Screen in which all other widgets are contained and rendered.
static void showTrackInfo(MusicMetadata *mdata)
int GetCurrentPos() const
MythMenu * createPlaylistOptionsMenu(void)
static void playFirstTrack()
void removeAllTracks(void)
Definition: playlist.cpp:87
void setVisual(const QString &name)
Definition: mainvisual.cpp:81
static Type VolumeChangeEvent
Definition: musicplayer.h:41
void switchToMusic(const QString &artist, const QString &album, const QString &track)
Definition: lcddevice.cpp:563
int m_currentTrack
Definition: musiccommon.h:155
MusicMetadata * getNextMetadata(void)
get the metadata for the next track in the playlist
virtual void ResetMap(const InfoMap &infoMap)
static Type Paused
Definition: output.h:64
void SetSearchFields(const QString &fields)
static Type AlbumArtChangedEvent
Definition: musicplayer.h:48
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:132
void DisplayState(const QString &state, const QString &name)
void Push(bool lock=false)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
MythUIButton * m_ffButton
Definition: musiccommon.h:198
void switchView(MusicView view)
void activePlaylistChanged(int trackID, bool deleted)
void toMap(InfoMap &metadataMap, const QString &prefix="")
void seekforward(void)
static Type TrackStatsChangedEvent
Definition: musicplayer.h:47
void setRepeatMode(RepeatMode mode)
Definition: musicplayer.h:181
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
AllMusic * m_all_music
Definition: musicdata.h:54
bool CreateCommon(void)
Definition: musiccommon.cpp:81
Provide a dialog to quickly find an entry in a list.
MythUIButtonListItem * GetItemCurrent() const
static Type Stopped
Definition: output.h:65
MythMenu * createPlaylistMenu(void)
static void toggleUpmix(void)