MythTV  master
playlisteditorview.cpp
Go to the documentation of this file.
1 // C++
2 #include <cstdlib>
3 #include <iostream>
4 
5 // qt
6 #include <QKeyEvent>
7 
8 // MythTV
10 #include <libmythbase/mythdbcon.h>
11 #include <libmythbase/mythdirs.h>
17 #include <libmythui/mythuitext.h>
18 #include <libmythui/mythuiutils.h>
19 
20 // mythmusic
21 #include "mainvisual.h"
22 #include "musiccommon.h"
23 #include "musicdata.h"
24 #include "playlistcontainer.h"
25 #include "playlisteditorview.h"
26 #include "smartplaylist.h"
27 
29  const QString &name, const QString &action,
31  bool showArrow)
32  : MythGenericTree(name),
33  m_action(action),
34  m_check(check),
35  m_showArrow(showArrow)
36 {
37  if (!action.isEmpty())
38  setSelectable(true);
39 
40  if (parent)
41  {
42  parent->addNode(this);
43  parent->setDrawArrow(true);
44  }
45 }
46 
48 {
49  m_showArrow = flag;
50  if (m_buttonItem)
51  m_buttonItem->setDrawArrow(true);
52 }
53 
55 {
56  m_check = state;
57  if (m_buttonItem)
58  {
60  m_buttonItem->setChecked(m_check);
61  }
62 }
63 
65 {
66  auto *item = new MusicButtonItem(list, GetText());
67  item->SetData(QVariant::fromValue((MythGenericTree*) this));
68 
69  if (visibleChildCount() > 0)
70  item->setDrawArrow(true);
71 
72  if (m_showArrow)
73  item->setDrawArrow(true);
74 
75  item->setCheckable(m_check != MythUIButtonListItem::CantCheck);
76  item->setChecked(m_check);
77 
78  m_buttonItem = item;
79 
80  return item;
81 }
82 
84 
85 #define LOC QString("PlaylistEditorView: ")
86 #define LOC_WARN QString("PlaylistEditorView, Warning: ")
87 #define LOC_ERR QString("PlaylistEditorView, Error: ")
88 
90  const QString &layout, bool restorePosition)
91  :MusicCommon(parent, parentScreen, "playlisteditorview"),
92  m_layout(layout), m_restorePosition(restorePosition)
93 {
95  gCoreContext->SaveSetting("MusicPlaylistEditorView", layout);
96 }
97 
99 {
101 
103 
104  for (int x = 0; x < m_deleteList.count(); x++)
105  delete m_deleteList.at(x);
106  m_deleteList.clear();
107 
108  delete m_rootNode;
109 }
110 
112 {
113  bool err = false;
114 
115  QString windowName;
116 
117  if (m_layout == "gallery")
118  {
119  windowName = "playlisteditorview_gallery";
121  }
122  else
123  {
124  windowName = "playlisteditorview_tree";
126  }
127 
128  // Load the theme for this screen
129  err = LoadWindowFromXML("music-ui.xml", windowName, this);
130 
131  if (!err)
132  {
133  gPlayer->removeListener(this);
134  return false;
135  }
136 
137  // find common widgets available on any view
138  err = CreateCommon();
139 
140  // find widgets specific to this view
141  UIUtilE::Assign(this, m_playlistTree , "playlist_tree", &err);
142  UIUtilW::Assign(this, m_breadcrumbsText, "breadcrumbs", &err);
143  UIUtilW::Assign(this, m_positionText, "position", &err);
144 
145  if (err)
146  {
147  LOG(VB_GENERAL, LOG_ERR, QString("Cannot load screen '%1'").arg(windowName));
148  gPlayer->removeListener(this);
149  return false;
150  }
151 
152  createRootNode();
153 
155 
157 
158  QStringList route = gCoreContext->GetSetting("MusicTreeLastActive", "").split("\n");
159  restoreTreePosition(route);
160 
165 
169 
170  BuildFocusList();
171 
172  return true;
173 }
174 
176 {
177  if ((event->type() == MusicPlayerEvent::kMetadataChangedEvent) ||
178  (event->type() == MusicPlayerEvent::kAlbumArtChangedEvent))
179  { // NOLINT(bugprone-branch-clone)
180  // TODO: this could be more efficient
181  reloadTree();
182  }
183  else if ((event->type() == MusicPlayerEvent::kTrackRemovedEvent) ||
184  (event->type() == MusicPlayerEvent::kTrackAddedEvent) ||
185  (event->type() == MusicPlayerEvent::kAllTracksRemovedEvent))
186  {
188  }
189  else if (event->type() == MusicPlayerEvent::kPlaylistChangedEvent)
190  {
191  //TODO should just update the relevent playlist here
192  reloadTree();
193  }
194  else if (event->type() == MusicPlayerEvent::kCDChangedEvent)
195  {
196  //TODO should just update the cd node
197  reloadTree();
198  }
199  else if (event->type() == MythEvent::kMythEventMessage)
200  {
201  auto *me = dynamic_cast<MythEvent*>(event);
202  if (!me)
203  return;
204 
205  if (me->Message().startsWith("MUSIC_RESYNC_FINISHED"))
206  {
207  QStringList list = me->Message().simplified().split(' ');
208  if (list.size() == 4)
209  {
210  int added = list[1].toInt();
211  int removed = list[2].toInt();
212  int changed = list[3].toInt();
213 
214  // if something changed reload the tree
215  if (added || removed || changed)
216  reloadTree();
217  }
218  }
219  }
220  else if (event->type() == DialogCompletionEvent::kEventType)
221  {
222  auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
223 
224  // make sure the user didn't ESCAPE out of the menu
225  if ((dce == nullptr) || (dce->GetResult() < 0))
226  return;
227 
228  QString resultid = dce->GetId();
229  QString resulttext = dce->GetResultText();
230 
231  if (resultid == "smartplaylistmenu")
232  {
234  return;
235 
237  if (!node)
238  return;
239 
240  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
241  if (!mnode)
242  return;
243 
244  if (resulttext == tr("New Smart Playlist"))
245  {
246  QString category;
247  if (mnode->getAction() == "smartplaylistcategory")
248  category = mnode->GetText();
249 
251  auto* editor = new SmartPlaylistEditor(mainStack);
252 
253  if (!editor->Create())
254  {
255  delete editor;
256  return;
257  }
258 
259  editor->newSmartPlaylist(category);
260 
261  connect(editor, &SmartPlaylistEditor::smartPLChanged,
263 
264  mainStack->AddScreen(editor);
265  }
266  else if (resulttext == tr("Remove Smart Playlist"))
267  {
268  QString category = mnode->getParent()->GetText();
269  QString name = mnode->GetText();
270 
271  ShowOkPopup(tr("Are you sure you want to delete this Smart Playlist?\n"
272  "Category: %1 - Name: %2").arg(category, name),
274  }
275  else if (resulttext == tr("Edit Smart Playlist"))
276  {
277  QString category = mnode->getParent()->GetText();
278  QString name = mnode->GetText();
279 
281  auto* editor = new SmartPlaylistEditor(mainStack);
282 
283  if (!editor->Create())
284  {
285  delete editor;
286  return;
287  }
288 
289  editor->editSmartPlaylist(category, name);
290 
291  connect(editor, &SmartPlaylistEditor::smartPLChanged,
293 
294  mainStack->AddScreen(editor);
295  }
296  else if (resulttext == tr("Replace Tracks"))
297  {
300  }
301  else if (resulttext == tr("Add Tracks"))
302  {
305  }
306  else if (resulttext == tr("Play Now"))
307  { // cancel shuffles and repeats to play now
310  updateShuffleMode(true);
314  }
315  }
316  else if (resultid == "treeplaylistmenu")
317  {
319  return;
320 
322  if (!node)
323  return;
324 
325  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
326  if (!mnode)
327  return;
328 
329  if (resulttext == tr("Remove Playlist"))
330  {
331  QString name = mnode->GetText();
332 
333  ShowOkPopup(tr("Are you sure you want to delete this Playlist?\n"
334  "Name: %1").arg(name),
336  }
337  else if (resulttext == tr("Replace Tracks"))
338  {
341  }
342  else if (resulttext == tr("Add Tracks"))
343  {
346  }
347  else if (resulttext == tr("Play Now"))
348  { // cancel shuffles and repeats to play now
351  updateShuffleMode(true);
355  }
356  }
357  }
358 
360 }
361 
362 bool PlaylistEditorView::keyPressEvent(QKeyEvent *event)
363 {
364  // if there is a pending jump point pass the key press to the default handler
365  if (GetMythMainWindow()->IsExitingToMain())
366  {
367  // Just call the parent handler. It will properly clean up.
368  return MusicCommon::keyPressEvent(event);
369  }
370 
372  return true;
373 
374  QStringList actions;
375  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
376 
377  for (int i = 0; i < actions.size() && !handled; i++)
378  {
379  const QString& action = actions[i];
380  handled = true;
381 
382  if ((action == "EDIT" || action == "INFO") && GetFocusWidget() == m_playlistTree)
383  {
384  handled = false;
385 
387  if (node)
388  {
389  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
390  if (mnode)
391  {
392  if (mnode->getAction() == "smartplaylist" && action == "EDIT")
393  {
394  QString category = mnode->getParent()->GetText();
395  QString name = mnode->GetText();
396 
398  auto* editor = new SmartPlaylistEditor(mainStack);
399 
400  if (!editor->Create())
401  {
402  delete editor;
403  return true;
404  }
405 
406  editor->editSmartPlaylist(category, name);
407  connect(editor, &SmartPlaylistEditor::smartPLChanged,
409 
410  mainStack->AddScreen(editor);
411 
412  handled = true;
413  }
414  else if (mnode->getAction() == "smartplaylistcategory" && action == "EDIT")
415  {
416  QString category = mnode->GetText();
417 
419  auto* editor = new SmartPlaylistEditor(mainStack);
420 
421  if (!editor->Create())
422  {
423  delete editor;
424  return true;
425  }
426 
427  editor->newSmartPlaylist(category);
428 
429  connect(editor, &SmartPlaylistEditor::smartPLChanged,
431 
432  mainStack->AddScreen(editor);
433 
434  handled = true;
435  }
436  else if (mnode->getAction() == "trackid")
437  {
438  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(mnode->getInt());
439  if (mdata)
440  {
441  if (action == "INFO")
442  showTrackInfo(mdata);
443  else
444  editTrackInfo(mdata);
445  }
446 
447  handled = true;
448  }
449  }
450  }
451  }
452  else if (action == "DELETE" && GetFocusWidget() == m_playlistTree)
453  {
454  handled = false;
455 
457  if (node)
458  {
459  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
460  if (mnode)
461  {
462  if (mnode->getAction() == "smartplaylist")
463  {
464  QString category = mnode->getParent()->GetText();
465  QString name = mnode->GetText();
466 
467  ShowOkPopup(tr("Are you sure you want to delete this Smart Playlist?\n"
468  "Category: %1 - Name: %2").arg(category, name),
470  handled = true;
471  }
472  else if (mnode->getAction() == "playlist")
473  {
474  QString name = mnode->GetText();
475 
476  ShowOkPopup(tr("Are you sure you want to delete this Playlist?\n"
477  "Name: %1").arg(name),
479  handled = true;
480  }
481  }
482  }
483  }
484  else if (action == "MARK")
485  {
487  if (item)
488  treeItemClicked(item);
489  }
490  else if ((action == "PLAY") && (GetFocusWidget() == m_playlistTree))
491  {
493  if (item)
494  {
495  auto *node = item->GetData().value<MythGenericTree*>();
496  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
497 
498  if (mnode)
499  {
500  updateSonglist(mnode);
501 
502  if (m_songList.count() > 0)
503  {
506 
507  stopVisualizer();
508 
510 
511  if (m_mainvisual)
512  {
513  m_mainvisual->mutex()->lock();
515  m_mainvisual->mutex()->unlock();
516  }
517  }
518  else
519  {
520  handled = false;
521  }
522  }
523  }
524  }
525  else
526  {
527  handled = false;
528  }
529  }
530 
531  if (!handled && MusicCommon::keyPressEvent(event))
532  handled = true;
533 
534  return handled;
535 }
536 
538 {
539  m_songList.clear();
540 
541  if (node->getAction() == "playlists" ||
542  node->getAction() == "smartplaylists" ||
543  node->getAction() == "smartplaylistcategory")
544  { // NOLINT(bugprone-branch-clone)
545  }
546  else if (node->getAction() == "trackid" || node->getAction() == "cdtrack")
547  {
548  m_songList.append(node->getInt());
549  }
550  else if (node->getAction() == "all tracks" ||
551  node->getAction() == "albums" ||
552  node->getAction() == "compartists" ||
553  node->getAction() == "artists" ||
554  node->getAction() == "genres" ||
555  node->getAction() == "ratings" ||
556  node->getAction() == "years")
557  {
558  // get the list of tracks from the previous 'All Tracks' node
559  auto *allTracksNode = dynamic_cast<MusicGenericTree*>(node->getParent()->getChildAt(0));
560  if (allTracksNode)
561  {
562  for (int x = 0; x < allTracksNode->childCount(); x++)
563  {
564  MythGenericTree *trackNode = allTracksNode->getChildAt(x);
565  if (trackNode)
566  m_songList.append(trackNode->getInt());
567  }
568  }
569  }
570  else if (node->getAction() == "album" ||
571  node->getAction() == "artist" ||
572  node->getAction() == "genre" ||
573  node->getAction() == "rating" ||
574  node->getAction() == "year" ||
575  node->getAction() == "compilations" ||
576  node->getAction() == "compartist")
577  {
578  // get the list of tracks from the 'All Tracks' node
579  auto *allTracksNode = dynamic_cast<MusicGenericTree*>(node->getChildAt(0));
580  if (allTracksNode)
581  {
582  if (allTracksNode->childCount() == 0)
583  filterTracks(allTracksNode);
584 
585  for (int x = 0; x < allTracksNode->childCount(); x++)
586  {
587  MythGenericTree *trackNode = allTracksNode->getChildAt(x);
588  if (trackNode)
589  m_songList.append(trackNode->getInt());
590  }
591  }
592  }
593  else if (node->getAction() == "smartplaylist")
594  {
595  // add the selected smart playlist's tracks to the song list
596  QList<MythGenericTree*> *children = node->getAllChildren();
597  for (int x = 0; x < children->count(); x++)
598  {
599  MythGenericTree *childnode = children->at(x);
600  m_songList.append(childnode->getInt());
601  }
602  }
603  else if (node->getAction() == "playlist")
604  {
605  // get list of tracks to add from the playlist
606  int playlistID = node->getInt();
607  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(playlistID);
608 
609  if (playlist)
610  {
611  for (int x = 0; x < playlist->getTrackCount(); x++)
612  {
613  MusicMetadata *mdata = playlist->getSongAt(x);
614  if (mdata)
615  m_songList.append((int) mdata->ID());
616  }
617  }
618  }
619  else if (node->getAction() == "error")
620  {
621  // a smart playlist has returned no tracks etc.
622  }
623  else
624  {
625  // fall back to getting the tracks from the MetadataPtrList
626  auto *tracks = node->GetData().value<MetadataPtrList*>();
627  for (int x = 0; x < tracks->count(); x++)
628  {
629  MusicMetadata *mdata = tracks->at(x);
630  if (mdata)
631  m_songList.append((int)mdata->ID());
632  }
633  }
634 }
635 
637 {
639  {
642 
643  MythMenu *menu = nullptr;
644  auto *mnode = dynamic_cast<MusicGenericTree*>(m_playlistTree->GetCurrentNode());
645 
646  if (mnode)
647  {
648  if (mnode->getAction() == "smartplaylists" ||
649  mnode->getAction() == "smartplaylistcategory" ||
650  mnode->getAction() == "smartplaylist")
651  {
653  }
654  else if (mnode->getAction() == "playlists" ||
655  mnode->getAction() == "playlist")
656  {
658  }
659  else if ( // (mnode->getAction() == "trackid") ||
660  (mnode->getAction() == "error"))
661  {
662  }
663  else
664  {
666  }
667 
668  updateSonglist(mnode);
669  }
670 
671  if (menu)
672  {
673  menu->AddItem(tr("More Options"), nullptr, createMainMenu());
674 
675  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
676 
677  auto *menuPopup = new MythDialogBox(menu, popupStack, "actionmenu");
678 
679  if (menuPopup->Create())
680  popupStack->AddScreen(menuPopup);
681  else
682  delete menu;
683 
684  return;
685  }
686  }
687 
689 }
690 
692 {
693  MythMenu *menu = nullptr;
694 
696  {
697  auto *mnode = dynamic_cast<MusicGenericTree*>(m_playlistTree->GetCurrentNode());
698 
699  if (!mnode)
700  return nullptr;
701 
702  if (mnode->getAction() == "playlist")
703  {
704  menu = new MythMenu(tr("Playlist Actions"), this, "treeplaylistmenu");
706  {
707  menu->AddItem(tr("Play Now"));
708  menu->AddItem(tr("Add Tracks"));
709  }
710  else
711  {
712  menu->AddItem(tr("Add Tracks"));
713  menu->AddItem(tr("Play Now"));
714  }
715  menu->AddItem(tr("Replace Tracks"));
716  menu->AddItem(tr("Remove Playlist"));
717  }
718  }
719 
720  return menu;
721 }
722 
724 {
725  MythMenu *menu = nullptr;
726 
728  {
729  auto *mnode = dynamic_cast<MusicGenericTree*>(m_playlistTree->GetCurrentNode());
730 
731  if (!mnode)
732  return nullptr;
733 
734  if (mnode->getAction() == "smartplaylists" || mnode->getAction() == "smartplaylistcategory")
735  {
736  QString label = tr("Smart Playlist Actions");
737 
738  menu = new MythMenu(label, this, "smartplaylistmenu");
739 
740  menu->AddItem(tr("New Smart Playlist"));
741  }
742  else if (mnode->getAction() == "smartplaylist")
743  {
744  menu = new MythMenu(tr("Smart Playlist Actions"), this, "smartplaylistmenu");
745 
747  {
748  menu->AddItem(tr("Play Now"));
749  menu->AddItem(tr("Add Tracks"));
750  }
751  else
752  {
753  menu->AddItem(tr("Add Tracks"));
754  menu->AddItem(tr("Play Now"));
755  }
756  menu->AddItem(tr("Replace Tracks"));
757 
758  menu->AddItem(tr("Edit Smart Playlist"));
759  menu->AddItem(tr("New Smart Playlist"));
760  menu->AddItem(tr("Remove Smart Playlist"));
761  }
762  }
763 
764  return menu;
765 }
766 
767 // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks)
769 {
770  if (!m_rootNode)
771  m_rootNode = new MusicGenericTree(nullptr, "Root Music Node");
772 
773  auto *node = new MusicGenericTree(m_rootNode, tr("All Tracks"), "all tracks");
774  node->setDrawArrow(true);
775  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
776 
777  node = new MusicGenericTree(m_rootNode, tr("Albums"), "albums");
778  node->setDrawArrow(true);
779  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
780 
781  node = new MusicGenericTree(m_rootNode, tr("Artists"), "artists");
782  node->setDrawArrow(true);
783  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
784 
785  node = new MusicGenericTree(m_rootNode, tr("Genres"), "genres");
786  node->setDrawArrow(true);
787  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
788 #if 0
789  node = new MusicGenericTree(m_rootNode, tr("Tags"), "tags");
790  node->setDrawArrow(true);
791  node->SetData(QVariant::fromValue(gMusicData->all_music->getAllMetadata()));
792 #endif
793  node = new MusicGenericTree(m_rootNode, tr("Ratings"), "ratings");
794  node->setDrawArrow(true);
795  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
796 
797  node = new MusicGenericTree(m_rootNode, tr("Years"), "years");
798  node->setDrawArrow(true);
799  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
800 
801  node = new MusicGenericTree(m_rootNode, tr("Compilations"), "compilations");
802  node->setDrawArrow(true);
803 
805  auto *compTracks = new MetadataPtrList;
806  m_deleteList.append(compTracks);
807 
808  for (int x = 0; x < alltracks->count(); x++)
809  {
810  MusicMetadata *mdata = alltracks->at(x);
811  if (mdata)
812  {
813  if (mdata->Compilation())
814  compTracks->append(mdata);
815  }
816  }
817  node->SetData(QVariant::fromValue(compTracks));
818 
820  {
821  node = new MusicGenericTree(m_rootNode, tr("CD - %1").arg(gMusicData->m_all_music->getCDTitle()), "cd");
822  node->setDrawArrow(true);
823  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllCDMetadata()));
824  }
825 
826  node = new MusicGenericTree(m_rootNode, tr("Directory"), "directory");
827  node->setDrawArrow(true);
828  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
829 
830  node = new MusicGenericTree(m_rootNode, tr("Playlists"), "playlists");
831  node->setDrawArrow(true);
832 
833  node = new MusicGenericTree(m_rootNode, tr("Smart Playlists"), "smartplaylists");
834  node->setDrawArrow(true);
835 }
836 // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
837 
839 {
840  auto *node = item->GetData().value<MythGenericTree*>();
841  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
842 
843  if (!mnode || !gPlayer->getCurrentPlaylist() || mnode->getAction() == "error")
844  return;
845 
846  if (mnode->getAction() == "trackid")
847  {
848  if (gPlayer->getCurrentPlaylist()->checkTrack(mnode->getInt()))
849  {
850  // remove track from the current playlist
851  gPlayer->removeTrack(mnode->getInt());
852  mnode->setCheck(MythUIButtonListItem::NotChecked);
853  }
854  else if (MusicPlayer::getPlayNow())
855  {
856  gPlayer->addTrack(mnode->getInt(), false);
859  mnode->setCheck(MythUIButtonListItem::FullChecked);
860  }
861  else
862  {
863  // add track to the current playlist
864  gPlayer->addTrack(mnode->getInt(), true);
865  mnode->setCheck(MythUIButtonListItem::FullChecked);
866  }
867  }
868  else
869  {
870  ShowMenu();
871  }
872 }
873 
874 
876 {
877  auto *node = item->GetData().value<MythGenericTree*>();;
878  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
879 
880  if (!mnode)
881  return;
882 
883  if (item->GetText("*").isEmpty())
884  {
885  item->SetText(" ", "*");
886 
887  QString artFile;
888 
889  if (mnode->getAction() == "trackid")
890  {
891  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(mnode->getInt());
892  if (mdata)
893  artFile = mdata->getAlbumArtFile();
894  }
895  else if (mnode->getAction() == "album")
896  {
897  // hunt for a coverart image for the album
898  auto *tracks = node->GetData().value<MetadataPtrList*>();
899  for (int x = 0; x < tracks->count(); x++)
900  {
901  MusicMetadata *mdata = tracks->at(x);
902  if (mdata)
903  {
904  artFile = mdata->getAlbumArtFile();
905  if (!artFile.isEmpty())
906  break;
907  }
908  }
909  }
910  else if (mnode->getAction() == "compartist")
911  {
912  artFile = findIcon("artist", mnode->GetText().toLower());
913  }
914  else if (mnode->getAction() == "all tracks" || mnode->getAction() == "genres" ||
915  mnode->getAction() == "albums" || mnode->getAction() == "artists" ||
916  mnode->getAction() == "compartists"|| mnode->getAction() == "ratings" ||
917  mnode->getAction() == "years" || mnode->getAction() == "compilations" ||
918  mnode->getAction() == "cd" || mnode->getAction() == "directory" ||
919  mnode->getAction() == "playlists" || mnode->getAction() == "smartplaylists")
920  {
921  artFile = "blank.png";
922  }
923  else
924  {
925  artFile = findIcon(mnode->getAction(), mnode->GetText().toLower());
926  }
927 
928  QString state = "default";
929 
930  if (mnode->getAction() == "all tracks")
931  state = "alltracks";
932  else if (mnode->getAction() == "genres")
933  state = "genres";
934  else if (mnode->getAction() == "albums")
935  state = "albums";
936  else if (mnode->getAction() == "artists")
937  state = "artists";
938  else if (mnode->getAction() == "compartists")
939  state = "compartists";
940  else if (mnode->getAction() == "ratings")
941  state = "ratings";
942  else if (mnode->getAction() == "years")
943  state = "years";
944  else if (mnode->getAction() == "compilations")
945  state = "compilations";
946  else if (mnode->getAction() == "cd")
947  state = "cd";
948  else if (mnode->getAction() == "directory")
949  state = "directory";
950  else if (mnode->getAction() == "playlists")
951  state = "playlists";
952  else if (mnode->getAction() == "smartplaylists")
953  state = "smartplaylists";
954 
955  item->DisplayState(state, "nodetype");
956 
957  if (artFile.isEmpty())
958  item->SetImage("");
959  else
960  item->SetImage(artFile);
961  }
962 }
963 
965 {
966  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
967  if (!mnode)
968  return;
969 
970  if (m_breadcrumbsText)
971  {
972  QString route = node->getRouteByString().join(" -> ");
973  route = route.remove("Root Music Node -> ");
974  m_breadcrumbsText->SetText(route);
975  }
976 
977  if (m_positionText)
978  {
979  m_positionText->SetText(tr("%1 of %2").arg(node->getPosition() + 1)
980  .arg(node->siblingCount()));
981  }
982 
983  if (mnode->childCount() > 0 || mnode->getAction() == "trackid")
984  return;
985 
986  if (mnode->getAction() == "smartplaylists")
987  {
989  }
990  else if (mnode->getAction() == "smartplaylistcategory")
991  {
992  getSmartPlaylists(mnode);
993  }
994  else if (mnode->getAction() == "smartplaylist")
995  {
996  getSmartPlaylistTracks(mnode, mnode->getInt());
997  }
998  else if (mnode->getAction() == "playlists")
999  {
1000  getPlaylists(mnode);
1001  }
1002  else if (mnode->getAction() == "playlist")
1003  {
1004  getPlaylistTracks(mnode, mnode->getInt());
1005  }
1006  else if (mnode->getAction() == "cd")
1007  {
1008  getCDTracks(mnode);
1009  }
1010  else
1011  {
1012  filterTracks(mnode);
1013  }
1014 }
1015 
1017 {
1018  auto *tracks = node->GetData().value<MetadataPtrList*>();
1019 
1020  if (!tracks)
1021  return;
1022 
1023  if (node->getAction() == "all tracks")
1024  {
1025  QMultiMap<QString, int> map;
1026  bool isAlbum = false;
1027  auto *parentNode = dynamic_cast<MusicGenericTree*>(node->getParent());
1028 
1029  if (parentNode)
1030  isAlbum = parentNode->getAction() == "album";
1031 
1032  for (int x = 0; x < tracks->count(); x++)
1033  {
1034  MusicMetadata *mdata = tracks->at(x);
1035  if (mdata)
1036  {
1037  QString key = mdata->Title();
1038 
1039  // Add the track number if an album is selected
1040  if (isAlbum && mdata->Track() > 0)
1041  {
1042  key.prepend(QString::number(mdata->Track()) + " - ");
1043  if (mdata->Track() < 10)
1044  key.prepend("0");
1045 
1046  // Add the disc number if this is a multi-disc album
1047  if (mdata->DiscNumber() > 0)
1048  {
1049  key.prepend(QString::number(mdata->DiscNumber()) + "/");
1050  if (mdata->DiscNumber() < 10)
1051  key.prepend("0");
1052  }
1053  }
1054  map.insert(key, mdata->ID());
1055  }
1056  }
1057 
1058  auto i = map.constBegin();
1059  while (i != map.constEnd())
1060  {
1061  auto *newnode = new MusicGenericTree(node, i.key(), "trackid");
1062  newnode->setInt(i.value());
1063  newnode->setDrawArrow(false);
1064  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(newnode->getInt()) : false;
1066  ++i;
1067  }
1068 
1069  node->sortByString(); // Case-insensitive sort
1070  }
1071  else if (node->getAction() == "artists")
1072  {
1073  QMap<QString, MetadataPtrList*> map;
1074 
1075  for (int x = 0; x < tracks->count(); x++)
1076  {
1077  MusicMetadata *mdata = tracks->at(x);
1078  if (mdata)
1079  {
1080  if (map.contains(mdata->Artist()))
1081  {
1082  MetadataPtrList *filteredTracks = map.value(mdata->Artist());
1083  filteredTracks->append(mdata);
1084  }
1085  else
1086  {
1087  auto *filteredTracks = new MetadataPtrList;
1088  m_deleteList.append(filteredTracks);
1089  filteredTracks->append(mdata);
1090  map.insert(mdata->Artist(), filteredTracks);
1091  }
1092  }
1093  }
1094 
1095  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1096  while (i != map.constEnd())
1097  {
1098  auto *newnode = new MusicGenericTree(node, i.key(), "artist");
1099  newnode->SetData(QVariant::fromValue(i.value()));
1100  ++i;
1101  }
1102 
1103  node->sortByString(); // Case-insensitive sort
1104  }
1105  else if (node->getAction() == "compartists")
1106  {
1107  QMap<QString, MetadataPtrList*> map;
1108 
1109  for (int x = 0; x < tracks->count(); x++)
1110  {
1111  MusicMetadata *mdata = tracks->at(x);
1112  if (mdata)
1113  {
1114  if (mdata->CompilationArtist() != mdata->Artist())
1115  {
1116  if (map.contains(mdata->CompilationArtist()))
1117  {
1118  MetadataPtrList *filteredTracks = map.value(mdata->CompilationArtist());
1119  filteredTracks->append(mdata);
1120  }
1121  else
1122  {
1123  auto *filteredTracks = new MetadataPtrList;
1124  m_deleteList.append(filteredTracks);
1125  filteredTracks->append(mdata);
1126  map.insert(mdata->CompilationArtist(), filteredTracks);
1127  }
1128  }
1129  }
1130  }
1131 
1132  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1133  while (i != map.constEnd())
1134  {
1135  auto *newnode = new MusicGenericTree(node, i.key(), "compartist");
1136  newnode->SetData(QVariant::fromValue(i.value()));
1137  ++i;
1138  }
1139 
1140  node->sortByString(); // Case-insensitive sort
1141  }
1142  else if (node->getAction() == "albums")
1143  {
1144  QMap<QString, MetadataPtrList*> map;
1145 
1146  for (int x = 0; x < tracks->count(); x++)
1147  {
1148  MusicMetadata *mdata = tracks->at(x);
1149  if (mdata)
1150  {
1151  if (map.contains(mdata->Album()))
1152  {
1153  MetadataPtrList *filteredTracks = map.value(mdata->Album());
1154  filteredTracks->append(mdata);
1155  }
1156  else
1157  {
1158  auto *filteredTracks = new MetadataPtrList;
1159  m_deleteList.append(filteredTracks);
1160  filteredTracks->append(mdata);
1161  map.insert(mdata->Album(), filteredTracks);
1162  }
1163  }
1164  }
1165 
1166  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1167  while (i != map.constEnd())
1168  {
1169  auto *newnode = new MusicGenericTree(node, i.key(), "album");
1170  newnode->SetData(QVariant::fromValue(i.value()));
1171  ++i;
1172  }
1173 
1174  node->sortByString(); // Case-insensitive sort
1175  }
1176  else if (node->getAction() == "genres")
1177  {
1178  QMap<QString, MetadataPtrList*> map;
1179 
1180  for (int x = 0; x < tracks->count(); x++)
1181  {
1182  MusicMetadata *mdata = tracks->at(x);
1183  if (mdata)
1184  {
1185  if (map.contains(mdata->Genre()))
1186  {
1187  MetadataPtrList *filteredTracks = map.value(mdata->Genre());
1188  filteredTracks->append(mdata);
1189  }
1190  else
1191  {
1192  auto *filteredTracks = new MetadataPtrList;
1193  m_deleteList.append(filteredTracks);
1194  filteredTracks->append(mdata);
1195  map.insert(mdata->Genre(), filteredTracks);
1196  }
1197  }
1198  }
1199 
1200  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1201  while (i != map.constEnd())
1202  {
1203  auto *newnode = new MusicGenericTree(node, i.key(), "genre");
1204  newnode->SetSortText(i.key()); // No manipulation of prefixes on genres
1205  newnode->SetData(QVariant::fromValue(i.value()));
1206  ++i;
1207  }
1208 
1209  node->sortByString(); // Case-insensitive sort
1210  }
1211  else if (node->getAction() == "ratings")
1212  {
1213  QMap<QString, MetadataPtrList*> map;
1214 
1215  for (int x = 0; x < tracks->count(); x++)
1216  {
1217  MusicMetadata *mdata = tracks->at(x);
1218  if (mdata)
1219  {
1220  QString ratingStr = tr("%n Star(s)", "", mdata->Rating());
1221  if (map.contains(ratingStr))
1222  {
1223  MetadataPtrList *filteredTracks = map.value(ratingStr);
1224  filteredTracks->append(mdata);
1225  }
1226  else
1227  {
1228  auto *filteredTracks = new MetadataPtrList;
1229  m_deleteList.append(filteredTracks);
1230  filteredTracks->append(mdata);
1231  map.insert(ratingStr, filteredTracks);
1232  }
1233  }
1234  }
1235 
1236  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1237  while (i != map.constEnd())
1238  {
1239  auto *newnode = new MusicGenericTree(node, i.key(), "rating");
1240  newnode->SetData(QVariant::fromValue(i.value()));
1241  ++i;
1242  }
1243  }
1244  else if (node->getAction() == "years")
1245  {
1246  QMap<QString, MetadataPtrList*> map;
1247 
1248  for (int x = 0; x < tracks->count(); x++)
1249  {
1250  MusicMetadata *mdata = tracks->at(x);
1251  if (mdata)
1252  {
1253  QString yearStr = QString("%1").arg(mdata->Year());
1254  if (map.contains(yearStr))
1255  {
1256  MetadataPtrList *filteredTracks = map.value(yearStr);
1257  filteredTracks->append(mdata);
1258  }
1259  else
1260  {
1261  auto *filteredTracks = new MetadataPtrList;
1262  m_deleteList.append(filteredTracks);
1263  filteredTracks->append(mdata);
1264  map.insert(yearStr, filteredTracks);
1265  }
1266  }
1267  }
1268 
1269  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1270  while (i != map.constEnd())
1271  {
1272  auto *newnode = new MusicGenericTree(node, i.key(), "year");
1273  newnode->SetData(QVariant::fromValue(i.value()));
1274  ++i;
1275  }
1276  }
1277  else if (node->getAction() == "directory")
1278  {
1279  QMap<QString, MetadataPtrList*> map;
1280 
1281  // which directories have we already filtered by
1282  QString dir;
1283  MusicGenericTree *climber = node;
1284  while (climber)
1285  {
1286  dir = climber->GetText() + '/' + dir;
1287  climber = dynamic_cast<MusicGenericTree *>(climber->getParent());
1288  }
1289 
1290  // remove the top two nodes
1291  QString top2 = "Root Music Node/" + tr("Directory") + '/';
1292  if (dir.startsWith(top2))
1293  dir = dir.mid(top2.length());
1294 
1295  for (int x = 0; x < tracks->count(); x++)
1296  {
1297  MusicMetadata *mdata = tracks->at(x);
1298  if (mdata)
1299  {
1300  QString filename = mdata->Filename(false);
1301 
1302  if (filename.startsWith(dir))
1303  filename = filename.mid(dir.length());
1304 
1305  QStringList dirs = filename.split("/");
1306 
1307  QString key = dirs.count() > 1 ? dirs[0] : "[TRACK]" + dirs[0];
1308  if (map.contains(key))
1309  {
1310  MetadataPtrList *filteredTracks = map.value(key);
1311  filteredTracks->append(mdata);
1312  }
1313  else
1314  {
1315  auto *filteredTracks = new MetadataPtrList;
1316  m_deleteList.append(filteredTracks);
1317  filteredTracks->append(mdata);
1318  map.insert(key, filteredTracks);
1319  }
1320  }
1321  }
1322 
1323  // add directories first
1324  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1325  while (i != map.constEnd())
1326  {
1327  if (!i.key().startsWith("[TRACK]"))
1328  {
1329  auto *newnode = new MusicGenericTree(node, i.key(), "directory");
1330  newnode->SetData(QVariant::fromValue(i.value()));
1331  }
1332  ++i;
1333  }
1334 
1335  // now add tracks
1336  i = map.constBegin();
1337  while (i != map.constEnd())
1338  {
1339  if (i.key().startsWith("[TRACK]"))
1340  {
1341  auto *newnode = new MusicGenericTree(node, i.key().mid(7), "trackid");
1342  newnode->setInt(i.value()->at(0)->ID());
1343  newnode->setDrawArrow(false);
1344  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(newnode->getInt()) : false;
1346  }
1347  ++i;
1348  }
1349  }
1350  else if (node->getAction() == "artist" || node->getAction() == "compartist" ||
1351  node->getAction() == "album" || node->getAction() == "genre" ||
1352  node->getAction() == "rating" || node->getAction() == "year" ||
1353  node->getAction() == "compilations")
1354  {
1355  // which fields have we already filtered by
1356  QStringList fields;
1357  MusicGenericTree *climber = node;
1358  while (climber)
1359  {
1360  fields.append(climber->getAction());
1361  climber = dynamic_cast<MusicGenericTree *>(climber->getParent());
1362  }
1363 
1364  auto *newnode = new MusicGenericTree(node, tr("All Tracks"), "all tracks");
1365  newnode->setDrawArrow(true);
1366  newnode->SetData(node->GetData());
1367 
1368  if (!fields.contains("albums"))
1369  {
1370  newnode = new MusicGenericTree(node, tr("Albums"), "albums");
1371  newnode->setDrawArrow(true);
1372  newnode->SetData(node->GetData());
1373  }
1374 
1375  if (!fields.contains("artists"))
1376  {
1377  newnode = new MusicGenericTree(node, tr("Artists"), "artists");
1378  newnode->setDrawArrow(true);
1379  newnode->SetData(node->GetData());
1380  }
1381 
1382  if (!fields.contains("compartists"))
1383  {
1384  // only show the Compilation Artists node if we are one the Compilations branch
1385  bool showCompArtists = false;
1386  MusicGenericTree *mnode = node;
1387  do
1388  {
1389  if (mnode->getAction() == "compilations")
1390  {
1391  showCompArtists = true;
1392  break;
1393  }
1394 
1395  mnode = dynamic_cast<MusicGenericTree *>(mnode->getParent());
1396 
1397  } while (mnode);
1398 
1399  // only show the Comp. Artist if it differs from the Artist
1400  bool found = false;
1401  auto *tracks2 = node->GetData().value<MetadataPtrList*>();
1402  for (int x = 0; x < tracks2->count(); x++)
1403  {
1404  MusicMetadata *mdata = tracks2->at(x);
1405  if (mdata)
1406  {
1407  if (mdata->Artist() != mdata->CompilationArtist())
1408  {
1409  found = true;
1410  break;
1411  }
1412  }
1413  }
1414 
1415  if (showCompArtists && found)
1416  {
1417  newnode = new MusicGenericTree(node, tr("Compilation Artists"), "compartists");
1418  newnode->setDrawArrow(true);
1419  newnode->SetData(node->GetData());
1420  }
1421  }
1422 
1423  if (!fields.contains("genres"))
1424  {
1425  newnode = new MusicGenericTree(node, tr("Genres"), "genres");
1426  newnode->setDrawArrow(true);
1427  newnode->SetData(node->GetData());
1428  }
1429 #if 0
1430  if (!fields.contains("tags"))
1431  {
1432  newnode = new MusicGenericTree(node, tr("Tags"), "tags");
1433  newnode->setDrawArrow(true);
1434  newnode->SetData(node->GetData());
1435  }
1436 #endif
1437  if (!fields.contains("ratings"))
1438  {
1439  newnode = new MusicGenericTree(node, tr("Ratings"), "ratings");
1440  newnode->setDrawArrow(true);
1441  newnode->SetData(node->GetData());
1442  }
1443 
1444  if (!fields.contains("years"))
1445  {
1446  newnode = new MusicGenericTree(node, tr("Years"), "years");
1447  newnode->setDrawArrow(true);
1448  newnode->SetData(node->GetData());
1449  }
1450  }
1451 }
1452 
1454 {
1455  MSqlQuery query(MSqlQuery::InitCon());
1456 
1457  if (query.exec("SELECT categoryid, name FROM music_smartplaylist_categories ORDER BY name;"))
1458  {
1459  if (query.isActive() && query.size() > 0)
1460  {
1461  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1462  while (query.next())
1463  {
1464  // No memory leak. MusicGenericTree adds the new node
1465  // into a list of nodes maintained by its parent.
1466  auto *newnode =
1467  new MusicGenericTree(node, query.value(1).toString(), "smartplaylistcategory");
1468  newnode->setInt(query.value(0).toInt());
1469  }
1470  }
1471  }
1472  else
1473  {
1474  MythDB::DBError("Load smartplaylist categories", query);
1475  }
1476 }
1477 
1479 {
1480  int categoryid = node->getInt();
1481 
1482  MSqlQuery query(MSqlQuery::InitCon());
1483  query.prepare("SELECT smartplaylistid, name FROM music_smartplaylists WHERE categoryid = :CATEGORYID "
1484  "ORDER BY name;");
1485  query.bindValue(":CATEGORYID", categoryid);
1486  if (query.exec())
1487  {
1488  if (query.isActive() && query.size() > 0)
1489  {
1490  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1491  while (query.next())
1492  {
1493  // No memory leak. MusicGenericTree adds the new node
1494  // into a list of nodes maintained by its parent.
1495  auto *newnode =
1496  new MusicGenericTree(node, query.value(1).toString(), "smartplaylist");
1497  newnode->setInt(query.value(0).toInt());
1498  }
1499  }
1500  }
1501  else
1502  {
1503  MythDB::DBError("Load smartplaylist names", query);
1504  }
1505 }
1506 
1508 {
1509  MSqlQuery query(MSqlQuery::InitCon());
1510 
1511  // find smartplaylist
1512  QString matchType;
1513  QString orderBy;
1514  int limitTo = 0;
1515 
1516  query.prepare("SELECT smartplaylistid, matchtype, orderby, limitto "
1517  "FROM music_smartplaylists "
1518  "WHERE smartplaylistid = :SMARTPLAYLISTID;");
1519  query.bindValue(":SMARTPLAYLISTID", playlistID);
1520 
1521  if (query.exec())
1522  {
1523  if (query.isActive() && query.size() > 0)
1524  {
1525  query.first();
1526  matchType = (query.value(1).toString() == "All") ? " AND " : " OR ";
1527  orderBy = query.value(2).toString();
1528  limitTo = query.value(3).toInt();
1529  }
1530  else
1531  {
1532  LOG(VB_GENERAL, LOG_WARNING,
1533  LOC + QString("Cannot find smartplaylist: %1").arg(playlistID));
1534  return;
1535  }
1536  }
1537  else
1538  {
1539  MythDB::DBError("Find SmartPlaylist", query);
1540  return;
1541  }
1542 
1543  // get smartplaylist items
1544  QString whereClause = "WHERE ";
1545 
1546  query.prepare("SELECT field, operator, value1, value2 "
1547  "FROM music_smartplaylist_items "
1548  "WHERE smartplaylistid = :ID;");
1549  query.bindValue(":ID", playlistID);
1550  if (query.exec())
1551  {
1552  bool bFirst = true;
1553  while (query.next())
1554  {
1555  QString fieldName = query.value(0).toString();
1556  QString operatorName = query.value(1).toString();
1557  QString value1 = query.value(2).toString();
1558  QString value2 = query.value(3).toString();
1559  if (!bFirst)
1560  {
1561  whereClause += matchType + getCriteriaSQL(fieldName,
1562  operatorName, value1, value2);
1563  }
1564  else
1565  {
1566  bFirst = false;
1567  whereClause += " " + getCriteriaSQL(fieldName, operatorName,
1568  value1, value2);
1569  }
1570  }
1571  }
1572 
1573  // add order by clause
1574  whereClause += getOrderBySQL(orderBy);
1575 
1576  // add limit
1577  if (limitTo > 0)
1578  whereClause += " LIMIT " + QString::number(limitTo);
1579 
1580 
1581  // find the tracks for this smartplaylist
1582  QString theQuery;
1583 
1584  theQuery = "SELECT song_id, name FROM music_songs "
1585  "LEFT JOIN music_directories ON"
1586  " music_songs.directory_id=music_directories.directory_id "
1587  "LEFT JOIN music_artists ON"
1588  " music_songs.artist_id=music_artists.artist_id "
1589  "LEFT JOIN music_albums ON"
1590  " music_songs.album_id=music_albums.album_id "
1591  "LEFT JOIN music_genres ON"
1592  " music_songs.genre_id=music_genres.genre_id "
1593  "LEFT JOIN music_artists AS music_comp_artists ON "
1594  "music_albums.artist_id=music_comp_artists.artist_id ";
1595  if (whereClause.length() > 0)
1596  theQuery += whereClause;
1597 
1598  if (!query.exec(theQuery))
1599  {
1600  MythDB::DBError("Load songlist from query", query);
1601  return;
1602  }
1603 
1604  while (query.next())
1605  {
1606  auto *newnode =
1607  new MusicGenericTree(node, query.value(1).toString(), "trackid");
1608  newnode->setInt(query.value(0).toInt());
1609  newnode->setDrawArrow(false);
1610  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(newnode->getInt()) : false;
1612  }
1613 
1614  // check we found some tracks if not add something to let the user know
1615  if (node->childCount() == 0)
1616  {
1617  auto *newnode =
1618  new MusicGenericTree(node, tr("** No matching tracks **"), "error");
1619  newnode->setDrawArrow(false);
1620  }
1621 }
1622 
1624 {
1625  QList<Playlist*> *playlists = gMusicData->m_all_playlists->getPlaylists();
1626 
1627  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1628  for (int x =0; x < playlists->count(); x++)
1629  {
1630  Playlist *playlist = playlists->at(x);
1631  // No memory leak. MusicGenericTree adds the new node
1632  // into a list of nodes maintained by its parent.
1633  auto *newnode =
1634  new MusicGenericTree(node, playlist->getName(), "playlist");
1635  newnode->setInt(playlist->getID());
1636  }
1637 }
1638 
1640 {
1642 
1643  for (int x = 0; x < tracks->count(); x++)
1644  {
1645  MusicMetadata *mdata = tracks->at(x);
1646  QString title = QString("%1 - %2").arg(mdata->Track()).arg(mdata->FormatTitle());
1647  auto *newnode = new MusicGenericTree(node, title, "trackid");
1648  newnode->setInt(mdata->ID());
1649  newnode->setDrawArrow(false);
1650  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()) : false;
1652  }
1653 }
1654 
1656 {
1657  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(playlistID);
1658 
1659  if (playlist)
1660  {
1661  for (int x = 0; x < playlist->getTrackCount(); x++)
1662  {
1663  MusicMetadata *mdata = playlist->getSongAt(x);
1664  if (mdata)
1665  {
1666  auto *newnode = new MusicGenericTree(node, mdata->Title(), "trackid");
1667  newnode->setInt(mdata->ID());
1668  newnode->setDrawArrow(false);
1669  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()) : false;
1671  }
1672  }
1673  }
1674 
1675  // check we found some tracks if not add something to let the user know
1676  if (node->childCount() == 0)
1677  {
1678  auto *newnode =
1679  new MusicGenericTree(node, tr("** Empty Playlist!! **"), "error");
1680  newnode->setDrawArrow(false);
1681  }
1682 }
1683 
1685 {
1687 }
1688 
1690 {
1691  for (int x = 0; x < node->childCount(); x++)
1692  {
1693  auto *mnode = dynamic_cast<MusicGenericTree*>(node->getChildAt(x));
1694  if (mnode)
1695  {
1696  if (mnode->getAction() == "trackid")
1697  {
1698  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(mnode->getInt()) : false;
1700  }
1701  else
1702  {
1703  if (mnode->childCount())
1704  updateSelectedTracks(mnode);
1705  }
1706  }
1707  }
1708 }
1709 
1711 {
1712  QStringList route = m_playlistTree->GetCurrentNode()->getRouteByString();
1713 
1714  m_playlistTree->Reset();
1715 
1716  for (int x = 0; x < m_deleteList.count(); x++)
1717  delete m_deleteList.at(x);
1718  m_deleteList.clear();
1719 
1721  createRootNode();
1723 
1724  restoreTreePosition(route);
1725 }
1726 
1727 void PlaylistEditorView::restoreTreePosition(const QStringList &route)
1728 {
1729  if (route.count() < 2)
1730  return;
1731 
1732  // traverse up the tree creating each nodes children as we go
1733  MythGenericTree *node = m_rootNode;
1734  for (int x = 1 ; x < route.count(); x++)
1735  {
1736  node = node->getChildByName(route.at(x));
1737 
1738  if (node)
1739  treeNodeChanged(node);
1740  else
1741  break;
1742  }
1743 
1745 }
1746 
1748 {
1749  if (m_playlistTree)
1750  {
1751  QString route = m_playlistTree->GetCurrentNode()->getRouteByString().join("\n");
1752  gCoreContext->SaveSetting("MusicTreeLastActive", route);
1753  }
1754 }
1755 
1756 void PlaylistEditorView::smartPLChanged(const QString &category, const QString &name)
1757 {
1758  reloadTree();
1759 
1760  // move to the smart playlist in tree
1761  QStringList route;
1762  route << "Root Music Node" << tr("Smart Playlists") << category << name;
1763  restoreTreePosition(route);
1764 }
1765 
1767 {
1768  if (!ok)
1769  return;
1770 
1772  if (node)
1773  {
1774  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
1775  if (mnode)
1776  {
1777  if (mnode->getAction() == "smartplaylist")
1778  {
1779  QString category = mnode->getParent()->GetText();
1780  QString name = mnode->GetText();
1781 
1783  reloadTree();
1784  }
1785  }
1786  }
1787 }
1788 
1790 {
1791  if (!ok)
1792  return;
1793 
1795  if (node)
1796  {
1797  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
1798  if (mnode)
1799  {
1800  if (mnode->getAction() == "playlist")
1801  {
1802  int id = mnode->getInt();
1803 
1806  }
1807  }
1808  }
1809 }
MusicCommon::m_currentView
MusicView m_currentView
Definition: musiccommon.h:141
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
MusicGenericTree::setDrawArrow
void setDrawArrow(bool flag)
Definition: playlisteditorview.cpp:47
MusicGenericTree::setCheck
void setCheck(MythUIButtonListItem::CheckState state)
Definition: playlisteditorview.cpp:54
mythuibuttontree.h
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:317
MusicCommon::editTrackInfo
static void editTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:1947
playlistcontainer.h
PlaylistEditorView::updateSonglist
void updateSonglist(MusicGenericTree *node)
Definition: playlisteditorview.cpp:537
findIcon
QString findIcon(const QString &type, const QString &name, bool ignoreCache)
find an image for a artist or genre
Definition: musicutils.cpp:34
MusicGenericTree::MusicGenericTree
MusicGenericTree(MusicGenericTree *parent, const QString &name, const QString &action="", MythUIButtonListItem::CheckState check=MythUIButtonListItem::CantCheck, bool showArrow=true)
Definition: playlisteditorview.cpp:28
MusicMetadata::Title
QString Title() const
Definition: musicmetadata.h:161
gPlayer
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
PlaylistEditorView::getSmartPlaylistCategories
static void getSmartPlaylistCategories(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1453
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
Playlist::getSongAt
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1096
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:977
MusicPlayer::setCurrentTrackPos
bool setCurrentTrackPos(int pos)
Definition: musicplayer.cpp:1064
mythuitext.h
MythEvent::kMythEventMessage
static const Type kMythEventMessage
Definition: mythevent.h:79
SmartPlaylistEditor::deleteSmartPlaylist
static bool deleteSmartPlaylist(const QString &category, const QString &name)
Definition: smartplaylist.cpp:1091
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:51
MusicMetadata::Genre
QString Genre() const
Definition: musicmetadata.h:174
MythGenericTree::GetText
QString GetText(const QString &name="") const
Definition: mythgenerictree.cpp:555
LOC
#define LOC
Definition: playlisteditorview.cpp:85
getOrderBySQL
QString getOrderBySQL(const QString &orderByFields)
Definition: smartplaylist.cpp:240
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3613
MythUIButtonListItem::FullChecked
@ FullChecked
Definition: mythuibuttonlist.h:48
MusicPlayer::SHUFFLE_OFF
@ SHUFFLE_OFF
Definition: musicplayer.h:175
PlaylistEditorView::treeItemClicked
void treeItemClicked(MythUIButtonListItem *item)
Definition: playlisteditorview.cpp:838
MusicCommon::CreateCommon
bool CreateCommon(void)
Definition: musiccommon.cpp:78
AllMusic::getAllCDMetadata
MetadataPtrList * getAllCDMetadata(void)
Definition: musicmetadata.h:447
MusicCommon::createPlaylistOptionsMenu
MythMenu * createPlaylistOptionsMenu(void)
Definition: musiccommon.cpp:2494
MusicMetadata::CompilationArtist
QString CompilationArtist() const
Definition: musicmetadata.h:137
PL_FIRSTNEW
@ PL_FIRSTNEW
Definition: playlist.h:33
MusicCommon::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: musiccommon.cpp:587
MusicGenericTree::m_buttonItem
QPointer< MusicButtonItem > m_buttonItem
Definition: playlisteditorview.h:58
MV_PLAYLISTEDITORTREE
@ MV_PLAYLISTEDITORTREE
Definition: musiccommon.h:35
PlaylistEditorView::PlaylistEditorView
PlaylistEditorView(MythScreenStack *parent, MythScreenType *parentScreen, const QString &layout, bool restorePosition=false)
Definition: playlisteditorview.cpp:89
MusicCommon::m_songList
QList< int > m_songList
Definition: musiccommon.h:170
MythGenericTree::visibleChildCount
uint visibleChildCount() const
Definition: mythgenerictree.h:101
MythGenericTree::getInt
int getInt() const
Definition: mythgenerictree.h:73
PlaylistOptions::insertPLOption
InsertPLOption insertPLOption
Definition: playlist.h:39
Playlist
Definition: playlist.h:45
Playlist::getName
QString getName(void)
Definition: playlist.h:106
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
MusicPlayer::getPlayNow
static bool getPlayNow(void)
Definition: musicplayer.cpp:230
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MythScreenStack
Definition: mythscreenstack.h:16
mythdbcon.h
MythGenericTree::GetData
QVariant GetData(void) const
Definition: mythgenerictree.h:98
MythUIButtonTree::GetItemCurrent
MythUIButtonListItem * GetItemCurrent(void) const
Return the currently selected list item.
Definition: mythuibuttontree.cpp:562
MusicPlayer::setShuffleMode
void setShuffleMode(ShuffleMode mode)
Definition: musicplayer.cpp:1274
MusicMetadata::ID
IdType ID() const
Definition: musicmetadata.h:217
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
MusicCommon::doUpdatePlaylist
void doUpdatePlaylist(void)
Definition: musiccommon.cpp:2637
PlaylistEditorView::Create
bool Create(void) override
Definition: playlisteditorview.cpp:111
MusicMetadata::Track
int Track() const
Definition: musicmetadata.h:198
MythGenericTree::getChildByName
MythGenericTree * getChildByName(const QString &a_name) const
Definition: mythgenerictree.cpp:377
PlaylistEditorView::getSmartPlaylistTracks
static void getSmartPlaylistTracks(MusicGenericTree *node, int playlistID)
Definition: playlisteditorview.cpp:1507
MythUIButtonListItem::CheckState
CheckState
Definition: mythuibuttonlist.h:44
PlaylistContainer::deletePlaylist
void deletePlaylist(int kill_me)
Definition: playlistcontainer.cpp:228
MusicCommon::showTrackInfo
static void showTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:2029
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
playlisteditorview.h
MusicMetadata
Definition: musicmetadata.h:80
MusicPlayerEvent::kMetadataChangedEvent
static const Type kMetadataChangedEvent
Definition: musicplayer.h:45
MusicPlayer::getCurrentPlaylist
Playlist * getCurrentPlaylist(void)
Definition: musicplayer.cpp:1637
PlaylistEditorView::getPlaylists
static void getPlaylists(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1623
mythdirs.h
MythUIButtonTree::AssignTree
bool AssignTree(MythGenericTree *tree)
Assign the root node of the tree to be displayed.
Definition: mythuibuttontree.cpp:213
MusicPlayer::removeListener
void removeListener(QObject *listener)
Definition: musicplayer.cpp:162
MV_PLAYLISTEDITORGALLERY
@ MV_PLAYLISTEDITORGALLERY
Definition: musiccommon.h:36
PL_CURRENT
@ PL_CURRENT
Definition: playlist.h:34
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:125
MainVisual::prepare
void prepare(void) override
Definition: mainvisual.cpp:138
musicutils.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
MusicPlayerEvent::kAllTracksRemovedEvent
static const Type kAllTracksRemovedEvent
Definition: musicplayer.h:44
PlaylistEditorView::updateSelectedTracks
void updateSelectedTracks(void)
Definition: playlisteditorview.cpp:1684
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:111
AllMusic::getAllMetadata
MetadataPtrList * getAllMetadata(void)
Definition: musicmetadata.h:446
PlaylistEditorView::smartPLChanged
void smartPLChanged(const QString &category, const QString &name)
Definition: playlisteditorview.cpp:1756
getCriteriaSQL
QString getCriteriaSQL(const QString &fieldName, const QString &operatorName, QString value1, QString value2)
Definition: smartplaylist.cpp:149
MusicCommon::m_playlistOptions
PlaylistOptions m_playlistOptions
Definition: musiccommon.h:166
PlaylistEditorView::m_deleteList
QList< MetadataPtrList * > m_deleteList
Definition: playlisteditorview.h:118
PlaylistEditorView::ShowMenu
void ShowMenu(void) override
Definition: playlisteditorview.cpp:636
MythUIButtonListItem::SetText
void SetText(const QString &text, const QString &name="", const QString &state="")
Definition: mythuibuttonlist.cpp:3319
MythGenericTree::getChildAt
MythGenericTree * getChildAt(uint reference) const
Definition: mythgenerictree.cpp:281
MythGenericTree::addNode
MythGenericTree * addNode(const QString &a_string, int an_int=0, bool selectable_flag=false, bool visible=true)
Definition: mythgenerictree.cpp:85
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
mythuiutils.h
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
MusicButtonItem
Definition: playlisteditorview.h:25
MusicCommon::m_moveTrackMode
bool m_moveTrackMode
Definition: musiccommon.h:152
MythUIButtonTree::itemClicked
void itemClicked(MythUIButtonListItem *item)
PlaylistEditorView::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: playlisteditorview.cpp:362
MusicGenericTree::CreateListButton
MythUIButtonListItem * CreateListButton(MythUIButtonList *list) override
Definition: playlisteditorview.cpp:64
mythlogging.h
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1111
PlaylistEditorView::deletePlaylist
void deletePlaylist(bool ok)
Definition: playlisteditorview.cpp:1789
MythGenericTree::sortByString
void sortByString()
Definition: mythgenerictree.cpp:419
MSqlQuery::first
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:822
MythGenericTree::getRouteByString
QStringList getRouteByString(void)
Definition: mythgenerictree.cpp:226
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:165
menu
static MythThemedMenu * menu
Definition: mythtv-setup.cpp:58
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
MusicGenericTree::getAction
QString getAction(void) const
Definition: playlisteditorview.h:47
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1277
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
MythTV::Visual::mutex
QMutex * mutex()
Definition: visual.h:26
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:204
Playlist::getTrackCount
int getTrackCount(void)
Definition: playlist.h:82
AllMusic::getCDTitle
QString getCDTitle(void) const
Definition: musicmetadata.h:439
MythGenericTree::childCount
int childCount(void) const
Definition: mythgenerictree.cpp:254
PlaylistContainer::getPlaylist
Playlist * getPlaylist(int id)
Definition: playlistcontainer.cpp:134
MusicCommon::stopVisualizer
void stopVisualizer(void)
Definition: musiccommon.cpp:1073
AllMusic::getCDTrackCount
int getCDTrackCount(void) const
Definition: musicmetadata.h:441
MusicCommon::m_mainvisual
MainVisual * m_mainvisual
Definition: musiccommon.h:144
SmartPlaylistEditor
Definition: smartplaylist.h:72
MythGenericTree::deleteAllChildren
void deleteAllChildren()
Definition: mythgenerictree.cpp:453
MythGenericTree::setSelectable
void setSelectable(bool flag)
Definition: mythgenerictree.h:106
PlaylistEditorView::deleteSmartPlaylist
void deleteSmartPlaylist(bool ok)
Definition: playlisteditorview.cpp:1766
MythUIButtonTree::GetCurrentNode
MythGenericTree * GetCurrentNode(void) const
Definition: mythuibuttontree.h:32
Playlist::checkTrack
bool checkTrack(MusicMetadata::IdType trackID) const
Definition: playlist.cpp:38
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1651
MusicPlayer::removeTrack
void removeTrack(int trackID)
Definition: musicplayer.cpp:1616
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MusicData::m_all_playlists
PlaylistContainer * m_all_playlists
Definition: musicdata.h:51
smartplaylist.h
PlaylistEditorView::~PlaylistEditorView
~PlaylistEditorView(void) override
Definition: playlisteditorview.cpp:98
PL_FIRST
@ PL_FIRST
Definition: playlist.h:32
PlaylistEditorView::reloadTree
void reloadTree(void)
Definition: playlisteditorview.cpp:1710
MythUIButtonTree::SetNodeByString
bool SetNodeByString(QStringList route)
Using a path based on the node string, set the currently selected node.
Definition: mythuibuttontree.cpp:281
MythGenericTree::getAllChildren
QList< MythGenericTree * > * getAllChildren() const
Definition: mythgenerictree.cpp:276
musicdata.h
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
MythGenericTree::siblingCount
int siblingCount(void) const
Definition: mythgenerictree.cpp:259
PlaylistEditorView::treeItemVisible
static void treeItemVisible(MythUIButtonListItem *item)
Definition: playlisteditorview.cpp:875
musiccommon.h
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:46
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:149
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:23
PL_INSERTATEND
@ PL_INSERTATEND
Definition: playlist.h:26
MusicGenericTree
Definition: playlisteditorview.h:38
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3368
MythGenericTree::getPosition
int getPosition(void)
Definition: mythgenerictree.cpp:205
MusicPlayerEvent::kCDChangedEvent
static const Type kCDChangedEvent
Definition: musicplayer.h:48
MusicCommon::createMainMenu
MythMenu * createMainMenu(void)
Definition: musiccommon.cpp:2277
PlaylistEditorView::getCDTracks
static void getCDTracks(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1639
MythMenu
Definition: mythdialogbox.h:98
MythUIButtonTree::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttontree.cpp:236
PlaylistEditorView::restoreTreePosition
void restoreTreePosition(const QStringList &route)
Definition: playlisteditorview.cpp:1727
MusicCommon::updateShuffleMode
void updateShuffleMode(bool updateUIList=false)
Definition: musiccommon.cpp:322
MusicPlayer::setRepeatMode
void setRepeatMode(RepeatMode mode)
Definition: musicplayer.h:192
mythcorecontext.h
MythUIButtonTree::RemoveCurrentItem
void RemoveCurrentItem(bool deleteNode=false)
Remove the currently selected item from the tree.
Definition: mythuibuttontree.cpp:430
PlaylistEditorView::customEvent
void customEvent(QEvent *event) override
Definition: playlisteditorview.cpp:175
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:701
MythUIButtonListItem::SetImage
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
Definition: mythuibuttonlist.cpp:3479
MythGenericTree::getParent
MythGenericTree * getParent(void) const
Definition: mythgenerictree.cpp:370
MusicPlayer::addTrack
void addTrack(int trackID, bool updateUI)
Definition: musicplayer.cpp:1632
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:40
MythGenericTree
Definition: mythgenerictree.h:27
MusicMetadata::Compilation
bool Compilation() const
Definition: musicmetadata.h:251
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
MusicMetadata::FormatTitle
QString FormatTitle()
Definition: musicmetadata.cpp:963
DialogCompletionEvent::kEventType
static const Type kEventType
Definition: mythdialogbox.h:56
PlaylistEditorView::createPlaylistMenu
MythMenu * createPlaylistMenu(void)
Definition: playlisteditorview.cpp:691
mainvisual.h
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
PlaylistEditorView::m_positionText
MythUIText * m_positionText
Definition: playlisteditorview.h:122
build_compdb.action
action
Definition: build_compdb.py:9
PlaylistEditorView::createRootNode
void createRootNode(void)
Definition: playlisteditorview.cpp:768
PlaylistEditorView::saveTreePosition
void saveTreePosition(void)
Definition: playlisteditorview.cpp:1747
MythUIButtonListItem::CantCheck
@ CantCheck
Definition: mythuibuttonlist.h:45
MusicPlayerEvent::kTrackRemovedEvent
static const Type kTrackRemovedEvent
Definition: musicplayer.h:42
PlaylistOptions::playPLOption
PlayPLOption playPLOption
Definition: playlist.h:40
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
MetadataPtrList
QList< MusicMetadata * > MetadataPtrList
Definition: musicmetadata.h:395
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:52
PL_REPLACE
@ PL_REPLACE
Definition: playlist.h:24
MusicPlayerEvent::kTrackAddedEvent
static const Type kTrackAddedEvent
Definition: musicplayer.h:41
PlaylistEditorView::getPlaylistTracks
static void getPlaylistTracks(MusicGenericTree *node, int playlistID)
Definition: playlisteditorview.cpp:1655
MusicMetadata::Rating
int Rating() const
Definition: musicmetadata.h:238
PlaylistEditorView::getSmartPlaylists
static void getSmartPlaylists(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1478
MusicGenericTree::m_showArrow
bool m_showArrow
Definition: playlisteditorview.h:60
MusicCommon::updateUIPlaylist
void updateUIPlaylist(void)
Definition: musiccommon.cpp:2101
PlaylistEditorView::createSmartPlaylistMenu
MythMenu * createSmartPlaylistMenu(void)
Definition: playlisteditorview.cpp:723
Playlist::getID
int getID(void) const
Definition: playlist.h:111
SmartPlaylistEditor::smartPLChanged
void smartPLChanged(const QString &category, const QString &name)
PlaylistEditorView::treeNodeChanged
void treeNodeChanged(MythGenericTree *node)
Definition: playlisteditorview.cpp:964
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:887
PlaylistContainer::getPlaylists
QList< Playlist * > * getPlaylists(void)
Definition: playlistcontainer.h:73
PlaylistEditorView::m_playlistTree
MythUIButtonTree * m_playlistTree
Definition: playlisteditorview.h:120
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:191
build_compdb.filename
filename
Definition: build_compdb.py:21
PlaylistEditorView::m_layout
QString m_layout
Definition: playlisteditorview.h:115
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
PlaylistEditorView::m_rootNode
MusicGenericTree * m_rootNode
Definition: playlisteditorview.h:117
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:566
MusicGenericTree::m_check
MythUIButtonListItem::CheckState m_check
Definition: playlisteditorview.h:59
MusicCommon::customEvent
void customEvent(QEvent *event) override
Definition: musiccommon.cpp:1232
MusicPlayerEvent::kPlaylistChangedEvent
static const Type kPlaylistChangedEvent
Definition: musicplayer.h:49
MythUIButtonTree::itemVisible
void itemVisible(MythUIButtonListItem *item)
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
MusicMetadata::Year
int Year() const
Definition: musicmetadata.h:195
PlaylistEditorView::filterTracks
void filterTracks(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1016
MythUIButtonTree::nodeChanged
void nodeChanged(MythGenericTree *node)
MusicCommon
Definition: musiccommon.h:49
MusicPlayer::REPEAT_OFF
@ REPEAT_OFF
Definition: musicplayer.h:169
MusicCommon::ShowMenu
void ShowMenu(void) override
Definition: musiccommon.cpp:2263
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:904
MusicPlayerEvent::kAlbumArtChangedEvent
static const Type kAlbumArtChangedEvent
Definition: musicplayer.h:47
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
MusicMetadata::DiscNumber
int DiscNumber() const
Definition: musicmetadata.h:208
PlaylistEditorView::m_breadcrumbsText
MythUIText * m_breadcrumbsText
Definition: playlisteditorview.h:121