MythTV  master
playlisteditorview.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstdlib>
3 
4 // qt
5 #include <QKeyEvent>
6 
7 // myth
8 #include <mythcontext.h>
9 #include <mythdbcon.h>
10 #include <mythmainwindow.h>
11 #include <mythuibuttontree.h>
12 #include <mythuitext.h>
13 #include <mythuiutils.h>
14 #include <mythdialogbox.h>
15 #include <mythdirs.h>
16 #include <musicutils.h>
17 
18 // mythmusic
19 #include "musicdata.h"
20 #include "playlistcontainer.h"
21 #include "musiccommon.h"
22 #include "playlisteditorview.h"
23 #include "smartplaylist.h"
24 #include "mainvisual.h"
25 
27  const QString &name, const QString &action,
29  bool showArrow)
30  : MythGenericTree(name)
31 {
32  m_check = check;
33  m_action = action;
34  m_showArrow = showArrow;
35 
36  if (!action.isEmpty() && !action.isNull())
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 
735 {
736  if (!m_rootNode)
737  m_rootNode = new MusicGenericTree(nullptr, "Root Music Node");
738 
739  auto *node = new MusicGenericTree(m_rootNode, tr("All Tracks"), "all tracks");
740  node->setDrawArrow(true);
741  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
742 
743  node = new MusicGenericTree(m_rootNode, tr("Albums"), "albums");
744  node->setDrawArrow(true);
745  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
746 
747  node = new MusicGenericTree(m_rootNode, tr("Artists"), "artists");
748  node->setDrawArrow(true);
749  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
750 
751  node = new MusicGenericTree(m_rootNode, tr("Genres"), "genres");
752  node->setDrawArrow(true);
753  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
754 #if 0
755  node = new MusicGenericTree(m_rootNode, tr("Tags"), "tags");
756  node->setDrawArrow(true);
757  node->SetData(QVariant::fromValue(gMusicData->all_music->getAllMetadata()));
758 #endif
759  node = new MusicGenericTree(m_rootNode, tr("Ratings"), "ratings");
760  node->setDrawArrow(true);
761  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
762 
763  node = new MusicGenericTree(m_rootNode, tr("Years"), "years");
764  node->setDrawArrow(true);
765  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
766 
767  node = new MusicGenericTree(m_rootNode, tr("Compilations"), "compilations");
768  node->setDrawArrow(true);
769 
771  auto *compTracks = new MetadataPtrList;
772  m_deleteList.append(compTracks);
773 
774  for (int x = 0; x < alltracks->count(); x++)
775  {
776  MusicMetadata *mdata = alltracks->at(x);
777  if (mdata)
778  {
779  if (mdata->Compilation())
780  compTracks->append(mdata);
781  }
782  }
783  node->SetData(QVariant::fromValue(compTracks));
784 
786  {
787  node = new MusicGenericTree(m_rootNode, tr("CD - %1").arg(gMusicData->m_all_music->getCDTitle()), "cd");
788  node->setDrawArrow(true);
789  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllCDMetadata()));
790  }
791 
792  node = new MusicGenericTree(m_rootNode, tr("Directory"), "directory");
793  node->setDrawArrow(true);
794  node->SetData(QVariant::fromValue(gMusicData->m_all_music->getAllMetadata()));
795 
796  node = new MusicGenericTree(m_rootNode, tr("Playlists"), "playlists");
797  node->setDrawArrow(true);
798 
799  node = new MusicGenericTree(m_rootNode, tr("Smart Playlists"), "smartplaylists");
800  node->setDrawArrow(true);
801 }
802 
804 {
805  auto *node = item->GetData().value<MythGenericTree*>();
806  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
807 
808  if (!mnode || !gPlayer->getCurrentPlaylist() || mnode->getAction() == "error")
809  return;
810 
811  if (mnode->getAction() == "trackid")
812  {
813  if (gPlayer->getCurrentPlaylist()->checkTrack(mnode->getInt()))
814  {
815  // remove track from the current playlist
816  gPlayer->removeTrack(mnode->getInt());
817  mnode->setCheck(MythUIButtonListItem::NotChecked);
818  }
819  else
820  {
821  // add track to the current playlist
822  gPlayer->addTrack(mnode->getInt(), true);
823  mnode->setCheck(MythUIButtonListItem::FullChecked);
824  }
825  }
826  else
827  ShowMenu();
828 }
829 
830 
832 {
833  auto *node = item->GetData().value<MythGenericTree*>();;
834  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
835 
836  if (!mnode)
837  return;
838 
839  if (item->GetText("*").isEmpty())
840  {
841  item->SetText(" ", "*");
842 
843  QString artFile;
844 
845  if (mnode->getAction() == "trackid")
846  {
847  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(mnode->getInt());
848  if (mdata)
849  artFile = mdata->getAlbumArtFile();
850  }
851  else if (mnode->getAction() == "album")
852  {
853  // hunt for a coverart image for the album
854  auto *tracks = node->GetData().value<MetadataPtrList*>();
855  for (int x = 0; x < tracks->count(); x++)
856  {
857  MusicMetadata *mdata = tracks->at(x);
858  if (mdata)
859  {
860  artFile = mdata->getAlbumArtFile();
861  if (!artFile.isEmpty())
862  break;
863  }
864  }
865  }
866  else if (mnode->getAction() == "compartist")
867  {
868  artFile = findIcon("artist", mnode->GetText().toLower());
869  }
870  else if (mnode->getAction() == "all tracks" || mnode->getAction() == "genres" ||
871  mnode->getAction() == "albums" || mnode->getAction() == "artists" ||
872  mnode->getAction() == "compartists"|| mnode->getAction() == "ratings" ||
873  mnode->getAction() == "years" || mnode->getAction() == "compilations" ||
874  mnode->getAction() == "cd" || mnode->getAction() == "directory" ||
875  mnode->getAction() == "playlists" || mnode->getAction() == "smartplaylists")
876  {
877  artFile = "blank.png";
878  }
879  else
880  {
881  artFile = findIcon(mnode->getAction(), mnode->GetText().toLower());
882  }
883 
884  QString state = "default";
885 
886  if (mnode->getAction() == "all tracks")
887  state = "alltracks";
888  else if (mnode->getAction() == "genres")
889  state = "genres";
890  else if (mnode->getAction() == "albums")
891  state = "albums";
892  else if (mnode->getAction() == "artists")
893  state = "artists";
894  else if (mnode->getAction() == "compartists")
895  state = "compartists";
896  else if (mnode->getAction() == "ratings")
897  state = "ratings";
898  else if (mnode->getAction() == "years")
899  state = "years";
900  else if (mnode->getAction() == "compilations")
901  state = "compilations";
902  else if (mnode->getAction() == "cd")
903  state = "cd";
904  else if (mnode->getAction() == "directory")
905  state = "directory";
906  else if (mnode->getAction() == "playlists")
907  state = "playlists";
908  else if (mnode->getAction() == "smartplaylists")
909  state = "smartplaylists";
910 
911  item->DisplayState(state, "nodetype");
912 
913  if (artFile.isEmpty())
914  item->SetImage("");
915  else
916  item->SetImage(artFile);
917  }
918 }
919 
921 {
922  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
923  if (!mnode)
924  return;
925 
926  if (m_breadcrumbsText)
927  {
928  QString route = node->getRouteByString().join(" -> ");
929  route = route.remove("Root Music Node -> ");
930  m_breadcrumbsText->SetText(route);
931  }
932 
933  if (m_positionText)
934  {
935  m_positionText->SetText(tr("%1 of %2").arg(node->getPosition() + 1)
936  .arg(node->siblingCount()));
937  }
938 
939  if (mnode->childCount() > 0 || mnode->getAction() == "trackid")
940  return;
941 
942  if (mnode->getAction() == "smartplaylists")
943  {
945  }
946  else if (mnode->getAction() == "smartplaylistcategory")
947  {
948  getSmartPlaylists(mnode);
949  }
950  else if (mnode->getAction() == "smartplaylist")
951  {
952  getSmartPlaylistTracks(mnode, mnode->getInt());
953  }
954  else if (mnode->getAction() == "playlists")
955  {
956  getPlaylists(mnode);
957  }
958  else if (mnode->getAction() == "playlist")
959  {
960  getPlaylistTracks(mnode, mnode->getInt());
961  }
962  else if (mnode->getAction() == "cd")
963  {
964  getCDTracks(mnode);
965  }
966  else
967  filterTracks(mnode);
968 }
969 
971 {
972  auto *tracks = node->GetData().value<MetadataPtrList*>();
973 
974  if (!tracks)
975  return;
976 
977  if (node->getAction() == "all tracks")
978  {
979  QMultiMap<QString, int> map;
980  bool isAlbum = false;
981  auto *parentNode = dynamic_cast<MusicGenericTree*>(node->getParent());
982 
983  if (parentNode)
984  isAlbum = parentNode->getAction() == "album";
985 
986  for (int x = 0; x < tracks->count(); x++)
987  {
988  MusicMetadata *mdata = tracks->at(x);
989  if (mdata)
990  {
991  QString key = mdata->Title();
992 
993  // Add the track number if an album is selected
994  if (isAlbum && mdata->Track() > 0)
995  {
996  key.prepend(QString::number(mdata->Track()) + " - ");
997  if (mdata->Track() < 10)
998  key.prepend("0");
999 
1000  // Add the disc number if this is a multi-disc album
1001  if (mdata->DiscNumber() > 0)
1002  {
1003  key.prepend(QString::number(mdata->DiscNumber()) + "/");
1004  if (mdata->DiscNumber() < 10)
1005  key.prepend("0");
1006  }
1007  }
1008  map.insert(key, mdata->ID());
1009  }
1010  }
1011 
1012  auto i = map.constBegin();
1013  while (i != map.constEnd())
1014  {
1015  auto *newnode = new MusicGenericTree(node, i.key(), "trackid");
1016  newnode->setInt(i.value());
1017  newnode->setDrawArrow(false);
1018  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(newnode->getInt()) : false;
1020  ++i;
1021  }
1022 
1023  node->sortByString(); // Case-insensitive sort
1024  }
1025  else if (node->getAction() == "artists")
1026  {
1027  QMap<QString, MetadataPtrList*> map;
1028 
1029  for (int x = 0; x < tracks->count(); x++)
1030  {
1031  MusicMetadata *mdata = tracks->at(x);
1032  if (mdata)
1033  {
1034  if (map.contains(mdata->Artist()))
1035  {
1036  MetadataPtrList *filteredTracks = map.value(mdata->Artist());
1037  filteredTracks->append(mdata);
1038  }
1039  else
1040  {
1041  auto *filteredTracks = new MetadataPtrList;
1042  m_deleteList.append(filteredTracks);
1043  filteredTracks->append(mdata);
1044  map.insert(mdata->Artist(), filteredTracks);
1045  }
1046  }
1047  }
1048 
1049  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1050  while (i != map.constEnd())
1051  {
1052  auto *newnode = new MusicGenericTree(node, i.key(), "artist");
1053  newnode->SetData(QVariant::fromValue(i.value()));
1054  ++i;
1055  }
1056 
1057  node->sortByString(); // Case-insensitive sort
1058  }
1059  else if (node->getAction() == "compartists")
1060  {
1061  QMap<QString, MetadataPtrList*> map;
1062 
1063  for (int x = 0; x < tracks->count(); x++)
1064  {
1065  MusicMetadata *mdata = tracks->at(x);
1066  if (mdata)
1067  {
1068  if (mdata->CompilationArtist() != mdata->Artist())
1069  {
1070  if (map.contains(mdata->CompilationArtist()))
1071  {
1072  MetadataPtrList *filteredTracks = map.value(mdata->CompilationArtist());
1073  filteredTracks->append(mdata);
1074  }
1075  else
1076  {
1077  auto *filteredTracks = new MetadataPtrList;
1078  m_deleteList.append(filteredTracks);
1079  filteredTracks->append(mdata);
1080  map.insert(mdata->CompilationArtist(), filteredTracks);
1081  }
1082  }
1083  }
1084  }
1085 
1086  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1087  while (i != map.constEnd())
1088  {
1089  auto *newnode = new MusicGenericTree(node, i.key(), "compartist");
1090  newnode->SetData(QVariant::fromValue(i.value()));
1091  ++i;
1092  }
1093 
1094  node->sortByString(); // Case-insensitive sort
1095  }
1096  else if (node->getAction() == "albums")
1097  {
1098  QMap<QString, MetadataPtrList*> map;
1099 
1100  for (int x = 0; x < tracks->count(); x++)
1101  {
1102  MusicMetadata *mdata = tracks->at(x);
1103  if (mdata)
1104  {
1105  if (map.contains(mdata->Album()))
1106  {
1107  MetadataPtrList *filteredTracks = map.value(mdata->Album());
1108  filteredTracks->append(mdata);
1109  }
1110  else
1111  {
1112  auto *filteredTracks = new MetadataPtrList;
1113  m_deleteList.append(filteredTracks);
1114  filteredTracks->append(mdata);
1115  map.insert(mdata->Album(), filteredTracks);
1116  }
1117  }
1118  }
1119 
1120  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1121  while (i != map.constEnd())
1122  {
1123  auto *newnode = new MusicGenericTree(node, i.key(), "album");
1124  newnode->SetData(QVariant::fromValue(i.value()));
1125  ++i;
1126  }
1127 
1128  node->sortByString(); // Case-insensitive sort
1129  }
1130  else if (node->getAction() == "genres")
1131  {
1132  QMap<QString, MetadataPtrList*> map;
1133 
1134  for (int x = 0; x < tracks->count(); x++)
1135  {
1136  MusicMetadata *mdata = tracks->at(x);
1137  if (mdata)
1138  {
1139  if (map.contains(mdata->Genre()))
1140  {
1141  MetadataPtrList *filteredTracks = map.value(mdata->Genre());
1142  filteredTracks->append(mdata);
1143  }
1144  else
1145  {
1146  auto *filteredTracks = new MetadataPtrList;
1147  m_deleteList.append(filteredTracks);
1148  filteredTracks->append(mdata);
1149  map.insert(mdata->Genre(), filteredTracks);
1150  }
1151  }
1152  }
1153 
1154  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1155  while (i != map.constEnd())
1156  {
1157  auto *newnode = new MusicGenericTree(node, i.key(), "genre");
1158  newnode->SetSortText(i.key()); // No manipulation of prefixes on genres
1159  newnode->SetData(QVariant::fromValue(i.value()));
1160  ++i;
1161  }
1162 
1163  node->sortByString(); // Case-insensitive sort
1164  }
1165  else if (node->getAction() == "ratings")
1166  {
1167  QMap<QString, MetadataPtrList*> map;
1168 
1169  for (int x = 0; x < tracks->count(); x++)
1170  {
1171  MusicMetadata *mdata = tracks->at(x);
1172  if (mdata)
1173  {
1174  QString ratingStr = tr("%n Star(s)", "", mdata->Rating());
1175  if (map.contains(ratingStr))
1176  {
1177  MetadataPtrList *filteredTracks = map.value(ratingStr);
1178  filteredTracks->append(mdata);
1179  }
1180  else
1181  {
1182  auto *filteredTracks = new MetadataPtrList;
1183  m_deleteList.append(filteredTracks);
1184  filteredTracks->append(mdata);
1185  map.insert(ratingStr, filteredTracks);
1186  }
1187  }
1188  }
1189 
1190  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1191  while (i != map.constEnd())
1192  {
1193  auto *newnode = new MusicGenericTree(node, i.key(), "rating");
1194  newnode->SetData(QVariant::fromValue(i.value()));
1195  ++i;
1196  }
1197  }
1198  else if (node->getAction() == "years")
1199  {
1200  QMap<QString, MetadataPtrList*> map;
1201 
1202  for (int x = 0; x < tracks->count(); x++)
1203  {
1204  MusicMetadata *mdata = tracks->at(x);
1205  if (mdata)
1206  {
1207  QString yearStr = QString("%1").arg(mdata->Year());
1208  if (map.contains(yearStr))
1209  {
1210  MetadataPtrList *filteredTracks = map.value(yearStr);
1211  filteredTracks->append(mdata);
1212  }
1213  else
1214  {
1215  auto *filteredTracks = new MetadataPtrList;
1216  m_deleteList.append(filteredTracks);
1217  filteredTracks->append(mdata);
1218  map.insert(yearStr, filteredTracks);
1219  }
1220  }
1221  }
1222 
1223  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1224  while (i != map.constEnd())
1225  {
1226  auto *newnode = new MusicGenericTree(node, i.key(), "year");
1227  newnode->SetData(QVariant::fromValue(i.value()));
1228  ++i;
1229  }
1230  }
1231  else if (node->getAction() == "directory")
1232  {
1233  QMap<QString, MetadataPtrList*> map;
1234 
1235  // which directories have we already filtered by
1236  QString dir;
1237  MusicGenericTree *climber = node;
1238  while (climber)
1239  {
1240  dir = climber->GetText() + '/' + dir;
1241  climber = dynamic_cast<MusicGenericTree *>(climber->getParent());
1242  }
1243 
1244  // remove the top two nodes
1245  QString top2 = "Root Music Node/" + tr("Directory") + '/';
1246  if (dir.startsWith(top2))
1247  dir = dir.mid(top2.length());
1248 
1249  for (int x = 0; x < tracks->count(); x++)
1250  {
1251  MusicMetadata *mdata = tracks->at(x);
1252  if (mdata)
1253  {
1254  QString filename = mdata->Filename(false);
1255 
1256  if (filename.startsWith(dir))
1257  filename = filename.mid(dir.length());
1258 
1259  QStringList dirs = filename.split("/");
1260 
1261  QString key = dirs.count() > 1 ? dirs[0] : "[TRACK]" + dirs[0];
1262  if (map.contains(key))
1263  {
1264  MetadataPtrList *filteredTracks = map.value(key);
1265  filteredTracks->append(mdata);
1266  }
1267  else
1268  {
1269  auto *filteredTracks = new MetadataPtrList;
1270  m_deleteList.append(filteredTracks);
1271  filteredTracks->append(mdata);
1272  map.insert(key, filteredTracks);
1273  }
1274  }
1275  }
1276 
1277  // add directories first
1278  QMap<QString, MetadataPtrList*>::const_iterator i = map.constBegin();
1279  while (i != map.constEnd())
1280  {
1281  if (!i.key().startsWith("[TRACK]"))
1282  {
1283  auto *newnode = new MusicGenericTree(node, i.key(), "directory");
1284  newnode->SetData(QVariant::fromValue(i.value()));
1285  }
1286  ++i;
1287  }
1288 
1289  // now add tracks
1290  i = map.constBegin();
1291  while (i != map.constEnd())
1292  {
1293  if (i.key().startsWith("[TRACK]"))
1294  {
1295  auto *newnode = new MusicGenericTree(node, i.key().mid(7), "trackid");
1296  newnode->setInt(i.value()->at(0)->ID());
1297  newnode->setDrawArrow(false);
1298  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(newnode->getInt()) : false;
1300  }
1301  ++i;
1302  }
1303  }
1304  else if (node->getAction() == "artist" || node->getAction() == "compartist" ||
1305  node->getAction() == "album" || node->getAction() == "genre" ||
1306  node->getAction() == "rating" || node->getAction() == "year" ||
1307  node->getAction() == "compilations")
1308  {
1309  // which fields have we already filtered by
1310  QStringList fields;
1311  MusicGenericTree *climber = node;
1312  while (climber)
1313  {
1314  fields.append(climber->getAction());
1315  climber = dynamic_cast<MusicGenericTree *>(climber->getParent());
1316  }
1317 
1318  auto *newnode = new MusicGenericTree(node, tr("All Tracks"), "all tracks");
1319  newnode->setDrawArrow(true);
1320  newnode->SetData(node->GetData());
1321 
1322  if (!fields.contains("albums"))
1323  {
1324  newnode = new MusicGenericTree(node, tr("Albums"), "albums");
1325  newnode->setDrawArrow(true);
1326  newnode->SetData(node->GetData());
1327  }
1328 
1329  if (!fields.contains("artists"))
1330  {
1331  newnode = new MusicGenericTree(node, tr("Artists"), "artists");
1332  newnode->setDrawArrow(true);
1333  newnode->SetData(node->GetData());
1334  }
1335 
1336  if (!fields.contains("compartists"))
1337  {
1338  // only show the Compilation Artists node if we are one the Compilations branch
1339  bool showCompArtists = false;
1340  MusicGenericTree *mnode = node;
1341  do
1342  {
1343  if (mnode->getAction() == "compilations")
1344  {
1345  showCompArtists = true;
1346  break;
1347  }
1348 
1349  mnode = dynamic_cast<MusicGenericTree *>(mnode->getParent());
1350 
1351  } while (mnode);
1352 
1353  // only show the Comp. Artist if it differs from the Artist
1354  bool found = false;
1355  auto *tracks2 = node->GetData().value<MetadataPtrList*>();
1356  for (int x = 0; x < tracks2->count(); x++)
1357  {
1358  MusicMetadata *mdata = tracks2->at(x);
1359  if (mdata)
1360  {
1361  if (mdata->Artist() != mdata->CompilationArtist())
1362  {
1363  found = true;
1364  break;
1365  }
1366  }
1367  }
1368 
1369  if (showCompArtists && found)
1370  {
1371  newnode = new MusicGenericTree(node, tr("Compilation Artists"), "compartists");
1372  newnode->setDrawArrow(true);
1373  newnode->SetData(node->GetData());
1374  }
1375  }
1376 
1377  if (!fields.contains("genres"))
1378  {
1379  newnode = new MusicGenericTree(node, tr("Genres"), "genres");
1380  newnode->setDrawArrow(true);
1381  newnode->SetData(node->GetData());
1382  }
1383 #if 0
1384  if (!fields.contains("tags"))
1385  {
1386  newnode = new MusicGenericTree(node, tr("Tags"), "tags");
1387  newnode->setDrawArrow(true);
1388  newnode->SetData(node->GetData());
1389  }
1390 #endif
1391  if (!fields.contains("ratings"))
1392  {
1393  newnode = new MusicGenericTree(node, tr("Ratings"), "ratings");
1394  newnode->setDrawArrow(true);
1395  newnode->SetData(node->GetData());
1396  }
1397 
1398  if (!fields.contains("years"))
1399  {
1400  newnode = new MusicGenericTree(node, tr("Years"), "years");
1401  newnode->setDrawArrow(true);
1402  newnode->SetData(node->GetData());
1403  }
1404  }
1405 }
1406 
1408 {
1409  MSqlQuery query(MSqlQuery::InitCon());
1410 
1411  if (query.exec("SELECT categoryid, name FROM music_smartplaylist_categories ORDER BY name;"))
1412  {
1413  if (query.isActive() && query.size() > 0)
1414  {
1415  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1416  while (query.next())
1417  {
1418  // No memory leak. MusicGenericTree adds the new node
1419  // into a list of nodes maintained by its parent.
1420  auto *newnode =
1421  new MusicGenericTree(node, query.value(1).toString(), "smartplaylistcategory");
1422  newnode->setInt(query.value(0).toInt());
1423  }
1424  }
1425  }
1426  else
1427  {
1428  MythDB::DBError("Load smartplaylist categories", query);
1429  }
1430 }
1431 
1433 {
1434  int categoryid = node->getInt();
1435 
1436  MSqlQuery query(MSqlQuery::InitCon());
1437  query.prepare("SELECT smartplaylistid, name FROM music_smartplaylists WHERE categoryid = :CATEGORYID "
1438  "ORDER BY name;");
1439  query.bindValue(":CATEGORYID", categoryid);
1440  if (query.exec())
1441  {
1442  if (query.isActive() && query.size() > 0)
1443  {
1444  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1445  while (query.next())
1446  {
1447  // No memory leak. MusicGenericTree adds the new node
1448  // into a list of nodes maintained by its parent.
1449  auto *newnode =
1450  new MusicGenericTree(node, query.value(1).toString(), "smartplaylist");
1451  newnode->setInt(query.value(0).toInt());
1452  }
1453  }
1454  }
1455  else
1456  MythDB::DBError("Load smartplaylist names", query);
1457 }
1458 
1460 {
1461  MSqlQuery query(MSqlQuery::InitCon());
1462 
1463  // find smartplaylist
1464  QString matchType;
1465  QString orderBy;
1466  int limitTo = 0;
1467 
1468  query.prepare("SELECT smartplaylistid, matchtype, orderby, limitto "
1469  "FROM music_smartplaylists "
1470  "WHERE smartplaylistid = :SMARTPLAYLISTID;");
1471  query.bindValue(":SMARTPLAYLISTID", playlistID);
1472 
1473  if (query.exec())
1474  {
1475  if (query.isActive() && query.size() > 0)
1476  {
1477  query.first();
1478  matchType = (query.value(1).toString() == "All") ? " AND " : " OR ";
1479  orderBy = query.value(2).toString();
1480  limitTo = query.value(3).toInt();
1481  }
1482  else
1483  {
1484  LOG(VB_GENERAL, LOG_WARNING,
1485  LOC + QString("Cannot find smartplaylist: %1").arg(playlistID));
1486  return;
1487  }
1488  }
1489  else
1490  {
1491  MythDB::DBError("Find SmartPlaylist", query);
1492  return;
1493  }
1494 
1495  // get smartplaylist items
1496  QString whereClause = "WHERE ";
1497 
1498  query.prepare("SELECT field, operator, value1, value2 "
1499  "FROM music_smartplaylist_items "
1500  "WHERE smartplaylistid = :ID;");
1501  query.bindValue(":ID", playlistID);
1502  if (query.exec())
1503  {
1504  bool bFirst = true;
1505  while (query.next())
1506  {
1507  QString fieldName = query.value(0).toString();
1508  QString operatorName = query.value(1).toString();
1509  QString value1 = query.value(2).toString();
1510  QString value2 = query.value(3).toString();
1511  if (!bFirst)
1512  {
1513  whereClause += matchType + getCriteriaSQL(fieldName,
1514  operatorName, value1, value2);
1515  }
1516  else
1517  {
1518  bFirst = false;
1519  whereClause += " " + getCriteriaSQL(fieldName, operatorName,
1520  value1, value2);
1521  }
1522  }
1523  }
1524 
1525  // add order by clause
1526  whereClause += getOrderBySQL(orderBy);
1527 
1528  // add limit
1529  if (limitTo > 0)
1530  whereClause += " LIMIT " + QString::number(limitTo);
1531 
1532 
1533  // find the tracks for this smartplaylist
1534  QString theQuery;
1535 
1536  theQuery = "SELECT song_id, name FROM music_songs "
1537  "LEFT JOIN music_directories ON"
1538  " music_songs.directory_id=music_directories.directory_id "
1539  "LEFT JOIN music_artists ON"
1540  " music_songs.artist_id=music_artists.artist_id "
1541  "LEFT JOIN music_albums ON"
1542  " music_songs.album_id=music_albums.album_id "
1543  "LEFT JOIN music_genres ON"
1544  " music_songs.genre_id=music_genres.genre_id "
1545  "LEFT JOIN music_artists AS music_comp_artists ON "
1546  "music_albums.artist_id=music_comp_artists.artist_id ";
1547  if (whereClause.length() > 0)
1548  theQuery += whereClause;
1549 
1550  if (!query.exec(theQuery))
1551  {
1552  MythDB::DBError("Load songlist from query", query);
1553  return;
1554  }
1555 
1556  while (query.next())
1557  {
1558  auto *newnode =
1559  new MusicGenericTree(node, query.value(1).toString(), "trackid");
1560  newnode->setInt(query.value(0).toInt());
1561  newnode->setDrawArrow(false);
1562  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(newnode->getInt()) : false;
1564  }
1565 
1566  // check we found some tracks if not add something to let the user know
1567  if (node->childCount() == 0)
1568  {
1569  auto *newnode =
1570  new MusicGenericTree(node, tr("** No matching tracks **"), "error");
1571  newnode->setDrawArrow(false);
1572  }
1573 }
1574 
1576 {
1577  QList<Playlist*> *playlists = gMusicData->m_all_playlists->getPlaylists();
1578 
1579  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1580  for (int x =0; x < playlists->count(); x++)
1581  {
1582  Playlist *playlist = playlists->at(x);
1583  // No memory leak. MusicGenericTree adds the new node
1584  // into a list of nodes maintained by its parent.
1585  auto *newnode =
1586  new MusicGenericTree(node, playlist->getName(), "playlist");
1587  newnode->setInt(playlist->getID());
1588  }
1589 }
1590 
1592 {
1594 
1595  for (int x = 0; x < tracks->count(); x++)
1596  {
1597  MusicMetadata *mdata = tracks->at(x);
1598  QString title = QString("%1 - %2").arg(mdata->Track()).arg(mdata->FormatTitle());
1599  auto *newnode = new MusicGenericTree(node, title, "trackid");
1600  newnode->setInt(mdata->ID());
1601  newnode->setDrawArrow(false);
1602  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()) : false;
1604  }
1605 }
1606 
1608 {
1609  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(playlistID);
1610 
1611  if (playlist)
1612  {
1613  for (int x = 0; x < playlist->getTrackCount(); x++)
1614  {
1615  MusicMetadata *mdata = playlist->getSongAt(x);
1616  if (mdata)
1617  {
1618  auto *newnode = new MusicGenericTree(node, mdata->Title(), "trackid");
1619  newnode->setInt(mdata->ID());
1620  newnode->setDrawArrow(false);
1621  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()) : false;
1623  }
1624  }
1625  }
1626 
1627  // check we found some tracks if not add something to let the user know
1628  if (node->childCount() == 0)
1629  {
1630  auto *newnode =
1631  new MusicGenericTree(node, tr("** Empty Playlist!! **"), "error");
1632  newnode->setDrawArrow(false);
1633  }
1634 }
1635 
1637 {
1639 }
1640 
1642 {
1643  for (int x = 0; x < node->childCount(); x++)
1644  {
1645  auto *mnode = dynamic_cast<MusicGenericTree*>(node->getChildAt(x));
1646  if (mnode)
1647  {
1648  if (mnode->getAction() == "trackid")
1649  {
1650  bool hasTrack = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->checkTrack(mnode->getInt()) : false;
1652  }
1653  else
1654  {
1655  if (mnode->childCount())
1656  updateSelectedTracks(mnode);
1657  }
1658  }
1659  }
1660 }
1661 
1663 {
1664  QStringList route = m_playlistTree->GetCurrentNode()->getRouteByString();
1665 
1666  m_playlistTree->Reset();
1667 
1668  for (int x = 0; x < m_deleteList.count(); x++)
1669  delete m_deleteList.at(x);
1670  m_deleteList.clear();
1671 
1673  createRootNode();
1675 
1676  restoreTreePosition(route);
1677 }
1678 
1679 void PlaylistEditorView::restoreTreePosition(const QStringList &route)
1680 {
1681  if (route.count() < 2)
1682  return;
1683 
1684  // traverse up the tree creating each nodes children as we go
1685  MythGenericTree *node = m_rootNode;
1686  for (int x = 1 ; x < route.count(); x++)
1687  {
1688  node = node->getChildByName(route.at(x));
1689 
1690  if (node)
1691  treeNodeChanged(node);
1692  else
1693  break;
1694  }
1695 
1697 }
1698 
1700 {
1701  if (m_playlistTree)
1702  {
1703  QString route = m_playlistTree->GetCurrentNode()->getRouteByString().join("\n");
1704  gCoreContext->SaveSetting("MusicTreeLastActive", route);
1705  }
1706 }
1707 
1708 void PlaylistEditorView::smartPLChanged(const QString &category, const QString &name)
1709 {
1710  reloadTree();
1711 
1712  // move to the smart playlist in tree
1713  QStringList route;
1714  route << "Root Music Node" << tr("Smart Playlists") << category << name;
1715  restoreTreePosition(route);
1716 }
1717 
1719 {
1720  if (!ok)
1721  return;
1722 
1724  if (node)
1725  {
1726  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
1727  if (mnode)
1728  {
1729  if (mnode->getAction() == "smartplaylist")
1730  {
1731  QString category = mnode->getParent()->GetText();
1732  QString name = mnode->GetText();
1733 
1735  reloadTree();
1736  }
1737  }
1738  }
1739 }
1740 
1742 {
1743  if (!ok)
1744  return;
1745 
1747  if (node)
1748  {
1749  auto *mnode = dynamic_cast<MusicGenericTree*>(node);
1750  if (mnode)
1751  {
1752  if (mnode->getAction() == "playlist")
1753  {
1754  int id = mnode->getInt();
1755 
1758  }
1759  }
1760  }
1761 }
MusicCommon::m_currentView
MusicView m_currentView
Definition: musiccommon.h:139
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:212
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:802
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:314
MusicCommon::editTrackInfo
static void editTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:1866
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:26
MusicMetadata::Title
QString Title() const
Definition: musicmetadata.h:162
gPlayer
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
PlaylistEditorView::getSmartPlaylistCategories
static void getSmartPlaylistCategories(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1407
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:211
Playlist::getSongAt
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1087
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:965
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:78
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:554
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:3506
PlaylistEditorView::treeItemClicked
void treeItemClicked(MythUIButtonListItem *item)
Definition: playlisteditorview.cpp:803
MusicCommon::CreateCommon
bool CreateCommon(void)
Definition: musiccommon.cpp:80
AllMusic::getAllCDMetadata
MetadataPtrList * getAllCDMetadata(void)
Definition: musicmetadata.h:449
MusicCommon::createPlaylistOptionsMenu
MythMenu * createPlaylistOptionsMenu(void)
Definition: musiccommon.cpp:2385
MusicMetadata::CompilationArtist
QString CompilationArtist() const
Definition: musicmetadata.h:138
MusicCommon::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: musiccommon.cpp:580
MusicGenericTree::m_buttonItem
QPointer< MusicButtonItem > m_buttonItem
Definition: playlisteditorview.h:57
PlaylistEditorView::PlaylistEditorView
PlaylistEditorView(MythScreenStack *parent, MythScreenType *parentScreen, const QString &layout, bool restorePosition=false)
Definition: playlisteditorview.cpp:88
MV_PLAYLISTEDITORTREE
@ MV_PLAYLISTEDITORTREE
Definition: musiccommon.h:34
MusicCommon::m_songList
QList< int > m_songList
Definition: musiccommon.h:168
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:201
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:554
MythUIButtonListItem::FullChecked
@ FullChecked
Definition: mythuibuttonlist.h:34
MusicMetadata::ID
IdType ID() const
Definition: musicmetadata.h:219
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
MusicCommon::doUpdatePlaylist
void doUpdatePlaylist(void)
Definition: musiccommon.cpp:2516
MusicPlayerEvent::TrackAddedEvent
static Type TrackAddedEvent
Definition: musicplayer.h:42
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:379
PlaylistEditorView::getSmartPlaylistTracks
static void getSmartPlaylistTracks(MusicGenericTree *node, int playlistID)
Definition: playlisteditorview.cpp:1459
PlaylistContainer::deletePlaylist
void deletePlaylist(int kill_me)
Definition: playlistcontainer.cpp:227
MusicCommon::showTrackInfo
static void showTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:1946
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:44
playlisteditorview.h
MusicMetadata
Definition: musicmetadata.h:80
MusicPlayerEvent::MetadataChangedEvent
static Type MetadataChangedEvent
Definition: musicplayer.h:46
MusicPlayer::getCurrentPlaylist
Playlist * getCurrentPlaylist(void)
Definition: musicplayer.cpp:1599
PlaylistEditorView::getPlaylists
static void getPlaylists(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1575
mythdirs.h
MythUIButtonTree::AssignTree
bool AssignTree(MythGenericTree *tree)
Assign the root node of the tree to be displayed.
Definition: mythuibuttontree.cpp:211
MusicPlayer::removeListener
void removeListener(QObject *listener)
Definition: musicplayer.cpp:159
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:126
MainVisual::prepare
void prepare(void) override
Definition: mainvisual.cpp:138
menu
static MythThemedMenu * menu
Definition: mythtv/programs/mythtv-setup/main.cpp:53
musicutils.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
MythUIButtonListItem::CheckState
CheckState
Definition: mythuibuttonlist.h:30
PlaylistEditorView::updateSelectedTracks
void updateSelectedTracks(void)
Definition: playlisteditorview.cpp:1636
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:112
AllMusic::getAllMetadata
MetadataPtrList * getAllMetadata(void)
Definition: musicmetadata.h:448
PlaylistEditorView::smartPLChanged
void smartPLChanged(const QString &category, const QString &name)
Definition: playlisteditorview.cpp:1708
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:164
PlaylistEditorView::m_deleteList
QList< MetadataPtrList * > m_deleteList
Definition: playlisteditorview.h:117
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:3271
MythGenericTree::getChildAt
MythGenericTree * getChildAt(uint reference) const
Definition: mythgenerictree.cpp:283
MythGenericTree::addNode
MythGenericTree * addNode(const QString &a_string, int an_int=0, bool selectable_flag=false, bool visible=true)
Definition: mythgenerictree.cpp:87
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
mythuiutils.h
MythUIButtonListItem
Definition: mythuibuttonlist.h:27
MusicButtonItem
Definition: playlisteditorview.h:24
MusicCommon::m_moveTrackMode
bool m_moveTrackMode
Definition: musiccommon.h:150
MythUIButtonTree::itemClicked
void itemClicked(MythUIButtonListItem *item)
MythUIButtonListItem::CantCheck
@ CantCheck
Definition: mythuibuttonlist.h:31
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:1113
PlaylistEditorView::deletePlaylist
void deletePlaylist(bool ok)
Definition: playlisteditorview.cpp:1741
MythGenericTree::sortByString
void sortByString()
Definition: mythgenerictree.cpp:421
MSqlQuery::first
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:812
MythGenericTree::getRouteByString
QStringList getRouteByString(void)
Definition: mythgenerictree.cpp:228
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
MusicGenericTree::getAction
QString getAction(void) const
Definition: playlisteditorview.h:46
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1261
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:200
MythTV::Visual::mutex
QMutex * mutex()
Definition: visual.h:26
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:205
Playlist::getTrackCount
int getTrackCount(void)
Definition: playlist.h:82
AllMusic::getCDTitle
QString getCDTitle(void) const
Definition: musicmetadata.h:441
MythGenericTree::childCount
int childCount(void) const
Definition: mythgenerictree.cpp:256
PlaylistContainer::getPlaylist
Playlist * getPlaylist(int id)
Definition: playlistcontainer.cpp:133
MV_PLAYLISTEDITORGALLERY
@ MV_PLAYLISTEDITORGALLERY
Definition: musiccommon.h:35
MusicCommon::stopVisualizer
void stopVisualizer(void)
Definition: musiccommon.cpp:1028
AllMusic::getCDTrackCount
int getCDTrackCount(void) const
Definition: musicmetadata.h:443
MusicCommon::m_mainvisual
MainVisual * m_mainvisual
Definition: musiccommon.h:142
SmartPlaylistEditor
Definition: smartplaylist.h:72
MythGenericTree::deleteAllChildren
void deleteAllChildren()
Definition: mythgenerictree.cpp:455
MythGenericTree::setSelectable
void setSelectable(bool flag)
Definition: mythgenerictree.h:106
PlaylistEditorView::deleteSmartPlaylist
void deleteSmartPlaylist(bool ok)
Definition: playlisteditorview.cpp:1718
MythUIButtonTree::GetCurrentNode
MythGenericTree * GetCurrentNode(void) const
Definition: mythuibuttontree.h:32
Playlist::checkTrack
bool checkTrack(MusicMetadata::IdType trackID) const
Definition: playlist.cpp:35
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3587
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1632
MusicPlayer::removeTrack
void removeTrack(int trackID)
Definition: musicplayer.cpp:1581
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MusicData::m_all_playlists
PlaylistContainer * m_all_playlists
Definition: musicdata.h:54
smartplaylist.h
PlaylistEditorView::~PlaylistEditorView
~PlaylistEditorView(void) override
Definition: playlisteditorview.cpp:97
MusicPlayerEvent::AllTracksRemovedEvent
static Type AllTracksRemovedEvent
Definition: musicplayer.h:45
PlaylistEditorView::reloadTree
void reloadTree(void)
Definition: playlisteditorview.cpp:1662
MythUIButtonTree::SetNodeByString
bool SetNodeByString(QStringList route)
Using a path based on the node string, set the currently selected node.
Definition: mythuibuttontree.cpp:279
MythGenericTree::getAllChildren
QList< MythGenericTree * > * getAllChildren() const
Definition: mythgenerictree.cpp:278
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:261
PlaylistEditorView::treeItemVisible
static void treeItemVisible(MythUIButtonListItem *item)
Definition: playlisteditorview.cpp:831
musiccommon.h
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:150
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:20
MusicGenericTree
Definition: playlisteditorview.h:37
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3312
MythGenericTree::getPosition
int getPosition(void)
Definition: mythgenerictree.cpp:207
PL_INSERTATEND
@ PL_INSERTATEND
Definition: playlist.h:26
MusicCommon::createMainMenu
MythMenu * createMainMenu(void)
Definition: musiccommon.cpp:2175
PlaylistEditorView::getCDTracks
static void getCDTracks(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1591
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:234
PlaylistEditorView::restoreTreePosition
void restoreTreePosition(const QStringList &route)
Definition: playlisteditorview.cpp:1679
MythUIButtonTree::RemoveCurrentItem
void RemoveCurrentItem(bool deleteNode=false)
Remove the currently selected item from the tree.
Definition: mythuibuttontree.cpp:426
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:692
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:3405
MythGenericTree::getParent
MythGenericTree * getParent(void) const
Definition: mythgenerictree.cpp:372
MusicPlayer::addTrack
void addTrack(int trackID, bool updateUI)
Definition: musicplayer.cpp:1594
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:878
MusicPlayerEvent::PlaylistChangedEvent
static Type PlaylistChangedEvent
Definition: musicplayer.h:50
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:115
MusicMetadata::Compilation
bool Compilation() const
Definition: musicmetadata.h:253
MusicPlayerEvent::TrackRemovedEvent
static Type TrackRemovedEvent
Definition: musicplayer.h:43
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:133
mythcontext.h
MusicMetadata::FormatTitle
QString FormatTitle()
Definition: musicmetadata.cpp:951
PlaylistEditorView::createPlaylistMenu
MythMenu * createPlaylistMenu(void)
Definition: playlisteditorview.cpp:676
mainvisual.h
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:101
PlaylistEditorView::m_positionText
MythUIText * m_positionText
Definition: playlisteditorview.h:121
build_compdb.action
action
Definition: build_compdb.py:9
PlaylistEditorView::createRootNode
void createRootNode(void)
Definition: playlisteditorview.cpp:734
MusicPlayerEvent::CDChangedEvent
static Type CDChangedEvent
Definition: musicplayer.h:49
PlaylistEditorView::saveTreePosition
void saveTreePosition(void)
Definition: playlisteditorview.cpp:1699
PlaylistOptions::playPLOption
PlayPLOption playPLOption
Definition: playlist.h:40
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:319
MetadataPtrList
QList< MusicMetadata * > MetadataPtrList
Definition: musicmetadata.h:397
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:55
PlaylistEditorView::getPlaylistTracks
static void getPlaylistTracks(MusicGenericTree *node, int playlistID)
Definition: playlisteditorview.cpp:1607
MusicMetadata::Rating
int Rating() const
Definition: musicmetadata.h:240
PlaylistEditorView::getSmartPlaylists
static void getSmartPlaylists(MusicGenericTree *node)
Definition: playlisteditorview.cpp:1432
MusicGenericTree::m_showArrow
bool m_showArrow
Definition: playlisteditorview.h:59
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)
MusicGenericTree::m_action
QString m_action
Definition: playlisteditorview.h:56
PlaylistEditorView::treeNodeChanged
void treeNodeChanged(MythGenericTree *node)
Definition: playlisteditorview.cpp:920
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:905
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:119
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:151
MusicPlayerEvent::AlbumArtChangedEvent
static Type AlbumArtChangedEvent
Definition: musicplayer.h:48
build_compdb.filename
filename
Definition: build_compdb.py:21
PlaylistEditorView::m_layout
QString m_layout
Definition: playlisteditorview.h:114
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
PlaylistEditorView::m_rootNode
MusicGenericTree * m_rootNode
Definition: playlisteditorview.h:116
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:558
MusicGenericTree::m_check
MythUIButtonListItem::CheckState m_check
Definition: playlisteditorview.h:58
MusicCommon::customEvent
void customEvent(QEvent *event) override
Definition: musiccommon.cpp:1184
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:970
MythUIButtonTree::nodeChanged
void nodeChanged(MythGenericTree *node)
MusicCommon
Definition: musiccommon.h:47
MusicCommon::ShowMenu
void ShowMenu(void) override
Definition: musiccommon.cpp:2161
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:922
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:32
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:827
MusicMetadata::DiscNumber
int DiscNumber() const
Definition: musicmetadata.h:210
PlaylistEditorView::m_breadcrumbsText
MythUIText * m_breadcrumbsText
Definition: playlisteditorview.h:120