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