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