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