MythTV  master
searchview.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstdlib>
3 
4 // qt
5 #include <QKeyEvent>
6 
7 // MythTV
8 #include <libmythbase/mythdb.h>
11 #include <libmythui/mythuitext.h>
13 
14 // mythmusic
15 #include "musiccommon.h"
16 #include "musicdata.h"
17 #include "searchview.h"
18 
20  :MusicCommon(parent, parentScreen,"searchview")
21 {
23 }
24 
26 {
27  // Load the theme for this screen
28  bool err = LoadWindowFromXML("music-ui.xml", "searchview", this);
29 
30  if (!err)
31  return false;
32 
33  // find common widgets available on any view
34  err = CreateCommon();
35 
36  // find widgets specific to this view
37  UIUtilE::Assign(this, m_fieldList, "field_list", &err);
38  UIUtilE::Assign(this, m_criteriaEdit, "criteria_edit", &err);
39  UIUtilW::Assign(this, m_matchesText, "matches_text", &err);
40  UIUtilE::Assign(this, m_tracksList, "tracks_list", &err);
41 
42  if (err)
43  {
44  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchview'");
45  return false;
46  }
47 
49 
51 
52  new MythUIButtonListItem(m_fieldList, tr("All Fields"),
53  QVariant::fromValue(0));
54  new MythUIButtonListItem(m_fieldList, tr("Artist"),
55  QVariant::fromValue(1));
56  new MythUIButtonListItem(m_fieldList, tr("Album"),
57  QVariant::fromValue(2));
58  new MythUIButtonListItem(m_fieldList, tr("Title"),
59  QVariant::fromValue(3));
60  new MythUIButtonListItem(m_fieldList, tr("Genre"),
61  QVariant::fromValue(4));
62  //new MythUIButtonListItem(m_fieldList, tr("Tags"),
63  // QVariant::fromValue(5));
64 
67 
70 
73 
75 
77 
78  return true;
79 }
80 
81 void SearchView::customEvent(QEvent *event)
82 {
83  bool handled = false;
84 
85  if (event->type() == MusicPlayerEvent::kTrackRemovedEvent ||
86  event->type() == MusicPlayerEvent::kTrackAddedEvent)
87  {
88  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
89 
90  if (!mpe)
91  return;
92 
93  int trackID = mpe->m_trackID;
94 
95  for (int x = 0; x < m_tracksList->GetCount(); x++)
96  {
98  auto *mdata = item->GetData().value<MusicMetadata*>();
99  if (mdata && (mdata->ID() == (MusicMetadata::IdType) trackID || trackID == -1))
100  {
102  item->DisplayState("on", "selectedstate");
103  else
104  item->DisplayState("off", "selectedstate");
105  }
106  }
107 
108  // call the default handler in MusicCommon so the playlist and UI is updated
110  handled = true;
111 
112  if (m_playTrack == 1 || (m_playTrack == -1 && MusicPlayer::getPlayNow()))
113  {
114  if (event->type() == MusicPlayerEvent::kTrackAddedEvent)
115  {
116  // make the added track current and play it
119  }
120  }
121  m_playTrack = -1; // use PlayNow preference or menu option
122  }
123  else if (event->type() == MusicPlayerEvent::kAllTracksRemovedEvent)
124  {
125  for (int x = 0; x < m_tracksList->GetCount(); x++)
126  {
128  if (item)
129  item->DisplayState("off", "selectedstate");
130  }
131  }
132  else if (event->type() == MusicPlayerEvent::kMetadataChangedEvent)
133  {
134  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
135 
136  if (!mpe)
137  return;
138 
139  uint trackID = mpe->m_trackID;
140 
141  for (int x = 0; x < m_tracksList->GetCount(); x++)
142  {
144  auto *mdata = item->GetData().value<MusicMetadata*>();
145  if (mdata && mdata->ID() == trackID)
146  {
147  InfoMap metadataMap;
148  mdata->toMap(metadataMap);
149  item->SetTextFromMap(metadataMap);
150  }
151  }
152 
153 // if (trackID == gPlayer->getCurrentMetadata()->ID())
154 // updateTrackInfo(gPlayer->getCurrentMetadata());
155  }
156  else if (event->type() == DialogCompletionEvent::kEventType)
157  {
158  auto *dce = dynamic_cast<DialogCompletionEvent *>(event);
159 
160  // make sure the user didn't ESCAPE out of the menu
161  if ((dce == nullptr) || (dce->GetResult() < 0))
162  return;
163 
164  QString resultid = dce->GetId();
165  QString resulttext = dce->GetResultText();
166  if (resultid == "searchviewmenu")
167  {
168  if (resulttext == tr("Add To Playlist") || resulttext == tr("Remove From Playlist"))
169  {
170  if (GetFocusWidget() == m_tracksList)
171  {
173  if (item)
174  {
175  m_playTrack = 0;
176  trackClicked(item);
177  }
178  }
179  }
180  else if (resulttext == tr("Play Now"))
181  {
182  if (GetFocusWidget() == m_tracksList)
183  {
185  if (item)
186  {
187  m_playTrack = 1;
188  trackClicked(item);
189  }
190  }
191  }
192  else if (resulttext == tr("Prefer Play Now"))
194  else if (resulttext == tr("Prefer Add Tracks"))
196  else if (resulttext == tr("Search List..."))
198  }
199  }
200 
201  if (!handled)
203 }
204 
205 bool SearchView::keyPressEvent(QKeyEvent *event)
206 {
208  return true;
209 
210  QStringList actions;
211  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
212 
213  for (int i = 0; i < actions.size() && !handled; i++)
214  {
215  QString action = actions[i];
216  handled = true;
217 
218  if (action == "INFO" || action == "EDIT")
219  {
220  if (GetFocusWidget() == m_tracksList)
221  {
223  {
224  auto *mdata = m_tracksList->GetItemCurrent()->GetData().value<MusicMetadata*>();
225  if (mdata)
226  {
227  if (action == "INFO")
228  showTrackInfo(mdata);
229  else
230  editTrackInfo(mdata);
231  }
232  }
233  }
234  else
235  handled = false;
236  }
237  else if (action == "PLAY")
238  {
239  if (GetFocusWidget() == m_tracksList)
240  {
242  if (item)
243  {
244  m_playTrack = 1;
245  trackClicked(item);
246  }
247  }
248  else
249  handled = false;
250  }
251  else
252  handled = false;
253  }
254 
255  if (!handled && MusicCommon::keyPressEvent(event))
256  handled = true;
257 
258  return handled;
259 }
260 
262 {
263  if (GetFocusWidget() == m_tracksList)
264  {
265  QString label = tr("Search Actions");
266 
267  auto *menu = new MythMenu(label, this, "searchviewmenu");
268 
270  if (item)
271  {
272  auto *mdata = item->GetData().value<MusicMetadata*>();
273  if (mdata)
274  {
276  menu->AddItem(tr("Remove From Playlist"));
277  else
278  {
280  {
281  menu->AddItem(tr("Play Now"));
282  menu->AddItem(tr("Add To Playlist"));
283  menu->AddItem(tr("Prefer Add To Playlist"));
284  }
285  else
286  {
287  menu->AddItem(tr("Add To Playlist"));
288  menu->AddItem(tr("Play Now"));
289  menu->AddItem(tr("Prefer Play Now"));
290  }
291  }
292  }
293  }
294 
296  menu->AddItem(tr("Search List..."));
297 
298  menu->AddItem(tr("More Options"), nullptr, createSubMenu());
299 
300  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
301 
302  auto *menuPopup = new MythDialogBox(menu, popupStack, "actionmenu");
303 
304  if (menuPopup->Create())
305  popupStack->AddScreen(menuPopup);
306  else
307  delete menu;
308  }
309  else
311 }
312 
314 {
316 }
317 
319 {
321 }
322 
324 {
325  m_tracksList->Reset();
326 
328 
329  if (!item)
330  return;
331 
332  QString searchStr = m_criteriaEdit->GetText();
333  int field = item->GetData().toInt();
334 
335  QString sql;
336  MSqlQuery query(MSqlQuery::InitCon());
337 
338  if (searchStr.isEmpty())
339  {
340  sql = "SELECT song_id "
341  "FROM music_songs ";
342 
343  query.prepare(sql);
344  }
345  else
346  {
347  switch(field)
348  {
349  case 1: // artist
350  {
351  sql = "SELECT song_id "
352  "FROM music_songs "
353  "LEFT JOIN music_artists ON "
354  " music_songs.artist_id=music_artists.artist_id "
355  "WHERE music_artists.artist_name LIKE '%" + searchStr + "%' ";
356  query.prepare(sql);
357  break;
358  }
359  case 2: // album
360  {
361  sql = "SELECT song_id "
362  "FROM music_songs "
363  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
364  "WHERE music_albums.album_name LIKE '%" + searchStr + "%' ";
365  query.prepare(sql);
366  break;
367  }
368  case 3: // title
369  {
370  sql = "SELECT song_id "
371  "FROM music_songs "
372  "WHERE music_songs.name LIKE '%" + searchStr + "%' ";
373  query.prepare(sql);
374  break;
375  }
376  case 4: // genre
377  {
378  sql = "SELECT song_id "
379  "FROM music_songs "
380  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
381  "WHERE music_genres.genre LIKE '%" + searchStr + "%' ";
382  query.prepare(sql);
383  break;
384  }
385  case 5: // tags
386  {
387  //TODO add tag query. Remove fallthrough once added.
388  [[fallthrough]];
389  }
390  case 0: // all fields
391  default:
392  {
393  sql = "SELECT song_id "
394  "FROM music_songs "
395  "LEFT JOIN music_artists ON "
396  " music_songs.artist_id=music_artists.artist_id "
397  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
398  "LEFT JOIN music_artists AS music_comp_artists ON "
399  " music_albums.artist_id=music_comp_artists.artist_id "
400  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
401  "WHERE music_songs.name LIKE '%" + searchStr + "%' "
402  "OR music_artists.artist_name LIKE '%" + searchStr + "%' "
403  "OR music_albums.album_name LIKE '%" + searchStr + "%' "
404  "OR music_genres.genre LIKE '%" + searchStr + "%' ";
405 
406  query.prepare(sql);
407  }
408  }
409  }
410 
411  if (!query.exec() || !query.isActive())
412  {
413  MythDB::DBError("Search music database", query);
414  return;
415  }
416 
417  while (query.next())
418  {
419  int trackid = query.value(0).toInt();
420 
421  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackid);
422  if (mdata)
423  {
424  auto *newitem = new MythUIButtonListItem(m_tracksList, "");
425  newitem->SetData(QVariant::fromValue(mdata));
426  InfoMap metadataMap;
427  mdata->toMap(metadataMap);
428  newitem->SetTextFromMap(metadataMap);
429 
431  newitem->DisplayState("on", "selectedstate");
432  else
433  newitem->DisplayState("off", "selectedstate");
434 
435  // TODO rating state etc
436  }
437  }
438 
440 
441  if (m_matchesText)
442  m_matchesText->SetText(QString("%1").arg(m_tracksList->GetCount()));
443 }
444 
446 {
447  if (!gPlayer->getCurrentPlaylist())
448  return;
449 
450  auto *mdata = item->GetData().value<MusicMetadata*>();
451  if (mdata)
452  {
453  if (gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()))
454  gPlayer->getCurrentPlaylist()->removeTrack(mdata->ID());
455  else
456  gPlayer->getCurrentPlaylist()->addTrack(mdata->ID(), true);
457  }
458 }
459 
461 {
462 
463  if (!item)
464  return;
465 
466  if (item->GetImageFilename().isEmpty())
467  {
468  auto *mdata = item->GetData().value<MusicMetadata*>();
469  if (mdata)
470  {
471  QString artFile = mdata->getAlbumArtFile();
472  if (artFile.isEmpty())
473  item->SetImage("");
474  else
475  item->SetImage(mdata->getAlbumArtFile());
476  }
477  else
478  item->SetImage("");
479  }
480 }
MusicCommon::m_currentView
MusicView m_currentView
Definition: musiccommon.h:141
SearchView::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: searchview.cpp:205
MythUIButtonList::GetItemAt
MythUIButtonListItem * GetItemAt(int pos) const
Definition: mythuibuttonlist.cpp:1673
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
MusicCommon::editTrackInfo
static void editTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:1879
gPlayer
MusicPlayer * gPlayer
Definition: musicplayer.cpp:37
SearchView::fieldSelected
void fieldSelected(MythUIButtonListItem *item)
Definition: searchview.cpp:313
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1587
mythuitext.h
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:52
SearchView::criteriaChanged
void criteriaChanged(void)
Definition: searchview.cpp:318
mythdb.h
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3554
MusicCommon::CreateCommon
bool CreateCommon(void)
Definition: musiccommon.cpp:76
MusicPlayerEvent
Definition: musicplayer.h:20
MusicCommon::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: musiccommon.cpp:573
MusicCommon::playlistItemClicked
void playlistItemClicked(MythUIButtonListItem *item)
Definition: musiccommon.cpp:1977
MusicCommon::createSubMenu
MythMenu * createSubMenu(void)
Definition: musiccommon.cpp:2248
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
MusicPlayer::getPlayNow
static bool getPlayNow(void)
Definition: musicplayer.cpp:229
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MythScreenStack
Definition: mythscreenstack.h:16
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:619
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
MusicMetadata
Definition: musicmetadata.h:80
MusicPlayerEvent::kMetadataChangedEvent
static const Type kMetadataChangedEvent
Definition: musicplayer.h:45
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:50
MusicPlayer::getCurrentPlaylist
Playlist * getCurrentPlaylist(void)
Definition: musicplayer.cpp:1611
SearchView::m_playTrack
int m_playTrack
Definition: searchview.h:42
SearchView::m_matchesText
MythUIText * m_matchesText
Definition: searchview.h:45
mythuibuttonlist.h
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1652
MusicPlayerEvent::kAllTracksRemovedEvent
static const Type kAllTracksRemovedEvent
Definition: musicplayer.h:44
SearchView::m_criteriaEdit
MythUITextEdit * m_criteriaEdit
Definition: searchview.h:44
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:113
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
MusicCommon::m_moveTrackMode
bool m_moveTrackMode
Definition: musiccommon.h:152
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
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:1112
MusicMetadata::toMap
void toMap(InfoMap &metadataMap, const QString &prefix="")
Definition: musicmetadata.cpp:1088
Playlist::removeTrack
void removeTrack(MusicMetadata::IdType trackID)
Definition: playlist.cpp:116
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:118
SearchView::m_fieldList
MythUIButtonList * m_fieldList
Definition: searchview.h:43
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:551
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1258
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
searchview.h
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
SearchView::SearchView
SearchView(MythScreenStack *parent, MythScreenType *parentScreen)
Definition: searchview.cpp:19
Playlist::addTrack
void addTrack(MusicMetadata::IdType trackID, bool update_display)
Given a tracks ID, add that track to this playlist.
Definition: playlist.cpp:62
MusicCommon::m_currentPlaylist
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:205
SearchView::trackClicked
static void trackClicked(MythUIButtonListItem *item)
Definition: searchview.cpp:445
SearchView::Create
bool Create(void) override
Definition: searchview.cpp:25
MusicPlayerEvent::m_trackID
int m_trackID
Definition: musicplayer.h:33
SearchView::ShowMenu
void ShowMenu(void) override
Definition: searchview.cpp:261
Playlist::checkTrack
bool checkTrack(MusicMetadata::IdType trackID) const
Definition: playlist.cpp:37
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3656
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1634
uint
unsigned int uint
Definition: compat.h:81
MythUIButtonList::itemVisible
void itemVisible(MythUIButtonListItem *item)
musicdata.h
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
MythUIButtonListItem::SetTextFromMap
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
Definition: mythuibuttonlist.cpp:3281
musiccommon.h
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:21
MusicMetadata::IdType
uint32_t IdType
Definition: musicmetadata.h:86
MythMenu
Definition: mythdialogbox.h:99
mythuitextedit.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:687
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:3420
MusicCommon::searchButtonList
void searchButtonList(void)
Definition: musiccommon.cpp:2180
SearchView::customEvent
void customEvent(QEvent *event) override
Definition: searchview.cpp:81
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
SearchView::m_tracksList
MythUIButtonList * m_tracksList
Definition: searchview.h:46
SearchView::trackVisible
static void trackVisible(MythUIButtonListItem *item)
Definition: searchview.cpp:460
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:132
DialogCompletionEvent::kEventType
static const Type kEventType
Definition: mythdialogbox.h:57
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:116
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1554
build_compdb.action
action
Definition: build_compdb.py:9
MusicPlayerEvent::kTrackRemovedEvent
static const Type kTrackRemovedEvent
Definition: musicplayer.h:42
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:323
MythUITextEdit::valueChanged
void valueChanged()
MV_SEARCH
@ MV_SEARCH
Definition: musiccommon.h:38
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:56
MusicPlayerEvent::kTrackAddedEvent
static const Type kTrackAddedEvent
Definition: musicplayer.h:41
MythUIButtonListItem::GetImageFilename
QString GetImageFilename(const QString &name="") const
Definition: mythuibuttonlist.cpp:3514
MusicPlayer::setPlayNow
static void setPlayNow(bool PlayNow)
whether we prefer Play Now over Add Tracks
Definition: musicplayer.cpp:225
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MusicCommon::customEvent
void customEvent(QEvent *event) override
Definition: musiccommon.cpp:1180
SearchView::updateTracksList
void updateTracksList(void)
Definition: searchview.cpp:323
MusicCommon
Definition: musiccommon.h:49
MusicCommon::ShowMenu
void ShowMenu(void) override
Definition: musiccommon.cpp:2191
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838