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