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>
12 #include <libmythui/mythuitext.h>
14 
15 // mythmusic
16 #include "musiccommon.h"
17 #include "musicdata.h"
18 #include "searchview.h"
19 
21  :MusicCommon(parent, parentScreen,"searchview")
22 {
24 }
25 
27 {
28  // Load the theme for this screen
29  bool err = LoadWindowFromXML("music-ui.xml", "searchview", this);
30 
31  if (!err)
32  return false;
33 
34  // find common widgets available on any view
35  err = CreateCommon();
36 
37  // find widgets specific to this view
38  UIUtilE::Assign(this, m_fieldList, "field_list", &err);
39  UIUtilE::Assign(this, m_criteriaEdit, "criteria_edit", &err);
40  UIUtilW::Assign(this, m_matchesText, "matches_text", &err);
41  UIUtilE::Assign(this, m_tracksList, "tracks_list", &err);
42 
43  if (err)
44  {
45  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchview'");
46  return false;
47  }
48 
50 
52 
53  new MythUIButtonListItem(m_fieldList, tr("All Fields"),
54  QVariant::fromValue(0));
55  new MythUIButtonListItem(m_fieldList, tr("Artist"),
56  QVariant::fromValue(1));
57  new MythUIButtonListItem(m_fieldList, tr("Album"),
58  QVariant::fromValue(2));
59  new MythUIButtonListItem(m_fieldList, tr("Title"),
60  QVariant::fromValue(3));
61  new MythUIButtonListItem(m_fieldList, tr("Genre"),
62  QVariant::fromValue(4));
63  //new MythUIButtonListItem(m_fieldList, tr("Tags"),
64  // QVariant::fromValue(5));
65 
68 
71 
74 
76 
78 
79  return true;
80 }
81 
82 void SearchView::customEvent(QEvent *event)
83 {
84  bool handled = false;
85 
86  if (event->type() == MusicPlayerEvent::kTrackRemovedEvent ||
87  event->type() == MusicPlayerEvent::kTrackAddedEvent)
88  {
89  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
90 
91  if (!mpe)
92  return;
93 
94  int trackID = mpe->m_trackID;
95 
96  for (int x = 0; x < m_tracksList->GetCount(); x++)
97  {
99  auto *mdata = item->GetData().value<MusicMetadata*>();
100  if (mdata && (mdata->ID() == (MusicMetadata::IdType) trackID || trackID == -1))
101  {
103  item->DisplayState("on", "selectedstate");
104  else
105  item->DisplayState("off", "selectedstate");
106  }
107  }
108 
109  // call the default handler in MusicCommon so the playlist and UI is updated
111  handled = true;
112 
113  if (m_playTrack == 1 || (m_playTrack == -1 && MusicPlayer::getPlayNow()))
114  {
115  if (event->type() == MusicPlayerEvent::kTrackAddedEvent)
116  {
117  // make the added track current and play it
120  }
121  }
122  m_playTrack = -1; // use PlayNow preference or menu option
123  }
124  else if (event->type() == MusicPlayerEvent::kAllTracksRemovedEvent)
125  {
126  for (int x = 0; x < m_tracksList->GetCount(); x++)
127  {
129  if (item)
130  item->DisplayState("off", "selectedstate");
131  }
132  }
133  else if (event->type() == MusicPlayerEvent::kMetadataChangedEvent)
134  {
135  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
136 
137  if (!mpe)
138  return;
139 
140  uint trackID = mpe->m_trackID;
141 
142  for (int x = 0; x < m_tracksList->GetCount(); x++)
143  {
145  auto *mdata = item->GetData().value<MusicMetadata*>();
146  if (mdata && mdata->ID() == trackID)
147  {
148  InfoMap metadataMap;
149  mdata->toMap(metadataMap);
150  item->SetTextFromMap(metadataMap);
151  }
152  }
153 
154 // if (trackID == gPlayer->getCurrentMetadata()->ID())
155 // updateTrackInfo(gPlayer->getCurrentMetadata());
156  }
157  else if (event->type() == DialogCompletionEvent::kEventType)
158  {
159  auto *dce = dynamic_cast<DialogCompletionEvent *>(event);
160 
161  // make sure the user didn't ESCAPE out of the menu
162  if ((dce == nullptr) || (dce->GetResult() < 0))
163  return;
164 
165  QString resultid = dce->GetId();
166  QString resulttext = dce->GetResultText();
167  if (resultid == "searchviewmenu")
168  {
169  if (resulttext == tr("Add To Playlist") || resulttext == tr("Remove From Playlist"))
170  {
171  if (GetFocusWidget() == m_tracksList)
172  {
174  if (item)
175  {
176  m_playTrack = 0;
177  trackClicked(item);
178  }
179  }
180  }
181  else if (resulttext == tr("Play Now"))
182  {
183  if (GetFocusWidget() == m_tracksList)
184  {
186  if (item)
187  {
188  m_playTrack = 1;
189  trackClicked(item);
190  }
191  }
192  }
193  else if (resulttext == tr("Prefer Play Now"))
194  {
196  }
197  else if (resulttext == tr("Prefer Add Tracks"))
198  {
200  }
201  else if (resulttext == tr("Search List..."))
202  {
204  }
205  }
206  }
207 
208  if (!handled)
210 }
211 
212 bool SearchView::keyPressEvent(QKeyEvent *event)
213 {
215  return true;
216 
217  QStringList actions;
218  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
219 
220  for (int i = 0; i < actions.size() && !handled; i++)
221  {
222  const QString& action = actions[i];
223  handled = true;
224 
225  if (action == "INFO" || action == "EDIT")
226  {
227  if (GetFocusWidget() == m_tracksList)
228  {
230  {
231  auto *mdata = m_tracksList->GetItemCurrent()->GetData().value<MusicMetadata*>();
232  if (mdata)
233  {
234  if (action == "INFO")
235  showTrackInfo(mdata);
236  else
237  editTrackInfo(mdata);
238  }
239  }
240  }
241  else
242  {
243  handled = false;
244  }
245  }
246  else if (action == "PLAY")
247  {
248  if (GetFocusWidget() == m_tracksList)
249  {
251  if (item)
252  {
253  m_playTrack = 1;
254  trackClicked(item);
255  }
256  }
257  else
258  {
259  handled = false;
260  }
261  }
262  else
263  {
264  handled = false;
265  }
266  }
267 
268  if (!handled && MusicCommon::keyPressEvent(event))
269  handled = true;
270 
271  return handled;
272 }
273 
275 {
276  if (GetFocusWidget() == m_tracksList)
277  {
278  QString label = tr("Search Actions");
279 
280  auto *menu = new MythMenu(label, this, "searchviewmenu");
281 
283  if (item)
284  {
285  auto *mdata = item->GetData().value<MusicMetadata*>();
286  if (mdata)
287  {
289  menu->AddItem(tr("Remove From Playlist"));
290  else
291  {
293  {
294  menu->AddItem(tr("Play Now"));
295  menu->AddItem(tr("Add To Playlist"));
296  menu->AddItem(tr("Prefer Add To Playlist"));
297  }
298  else
299  {
300  menu->AddItem(tr("Add To Playlist"));
301  menu->AddItem(tr("Play Now"));
302  menu->AddItem(tr("Prefer Play Now"));
303  }
304  }
305  }
306  }
307 
309  menu->AddItem(tr("Search List..."));
310 
311  menu->AddItem(tr("More Options"), nullptr, createSubMenu());
312 
313  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
314 
315  auto *menuPopup = new MythDialogBox(menu, popupStack, "actionmenu");
316 
317  if (menuPopup->Create())
318  popupStack->AddScreen(menuPopup);
319  else
320  delete menu;
321  }
322  else
323  {
325  }
326 }
327 
329 {
331 }
332 
334 {
336 }
337 
339 {
340  m_tracksList->Reset();
341 
343 
344  if (!item)
345  return;
346 
347  QString searchStr = m_criteriaEdit->GetText();
348  int field = item->GetData().toInt();
349 
350  QString sql;
351  MSqlQuery query(MSqlQuery::InitCon());
352 
353  if (searchStr.isEmpty())
354  {
355  sql = "SELECT song_id "
356  "FROM music_songs ";
357 
358  query.prepare(sql);
359  }
360  else
361  {
362  switch(field)
363  {
364  case 1: // artist
365  {
366  sql = "SELECT song_id "
367  "FROM music_songs "
368  "LEFT JOIN music_artists ON "
369  " music_songs.artist_id=music_artists.artist_id "
370  "WHERE music_artists.artist_name LIKE '%" + searchStr + "%' ";
371  query.prepare(sql);
372  break;
373  }
374  case 2: // album
375  {
376  sql = "SELECT song_id "
377  "FROM music_songs "
378  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
379  "WHERE music_albums.album_name LIKE '%" + searchStr + "%' ";
380  query.prepare(sql);
381  break;
382  }
383  case 3: // title
384  {
385  sql = "SELECT song_id "
386  "FROM music_songs "
387  "WHERE music_songs.name LIKE '%" + searchStr + "%' ";
388  query.prepare(sql);
389  break;
390  }
391  case 4: // genre
392  {
393  sql = "SELECT song_id "
394  "FROM music_songs "
395  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
396  "WHERE music_genres.genre LIKE '%" + searchStr + "%' ";
397  query.prepare(sql);
398  break;
399  }
400  case 5: // tags
401  {
402  //TODO add tag query. Remove fallthrough once added.
403  [[fallthrough]];
404  }
405  case 0: // all fields
406  default:
407  {
408  sql = "SELECT song_id "
409  "FROM music_songs "
410  "LEFT JOIN music_artists ON "
411  " music_songs.artist_id=music_artists.artist_id "
412  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
413  "LEFT JOIN music_artists AS music_comp_artists ON "
414  " music_albums.artist_id=music_comp_artists.artist_id "
415  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
416  "WHERE music_songs.name LIKE '%" + searchStr + "%' "
417  "OR music_artists.artist_name LIKE '%" + searchStr + "%' "
418  "OR music_albums.album_name LIKE '%" + searchStr + "%' "
419  "OR music_genres.genre LIKE '%" + searchStr + "%' ";
420 
421  query.prepare(sql);
422  }
423  }
424  }
425 
426  if (!query.exec() || !query.isActive())
427  {
428  MythDB::DBError("Search music database", query);
429  return;
430  }
431 
432  while (query.next())
433  {
434  int trackid = query.value(0).toInt();
435 
436  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackid);
437  if (mdata)
438  {
439  auto *newitem = new MythUIButtonListItem(m_tracksList, "");
440  newitem->SetData(QVariant::fromValue(mdata));
441  InfoMap metadataMap;
442  mdata->toMap(metadataMap);
443  newitem->SetTextFromMap(metadataMap);
444 
446  newitem->DisplayState("on", "selectedstate");
447  else
448  newitem->DisplayState("off", "selectedstate");
449 
450  // TODO rating state etc
451  }
452  }
453 
455 
456  if (m_matchesText)
457  m_matchesText->SetText(QString("%1").arg(m_tracksList->GetCount()));
458 }
459 
461 {
462  if (!gPlayer->getCurrentPlaylist())
463  return;
464 
465  auto *mdata = item->GetData().value<MusicMetadata*>();
466  if (mdata)
467  {
468  if (gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()))
469  gPlayer->getCurrentPlaylist()->removeTrack(mdata->ID());
470  else
471  gPlayer->getCurrentPlaylist()->addTrack(mdata->ID(), true);
472  }
473 }
474 
476 {
477 
478  if (!item)
479  return;
480 
481  if (item->GetImageFilename().isEmpty())
482  {
483  auto *mdata = item->GetData().value<MusicMetadata*>();
484  if (mdata)
485  {
486  QString artFile = mdata->getAlbumArtFile();
487  if (artFile.isEmpty())
488  item->SetImage("");
489  else
490  item->SetImage(mdata->getAlbumArtFile());
491  }
492  else
493  {
494  item->SetImage("");
495  }
496  }
497 }
MusicCommon::m_currentView
MusicView m_currentView
Definition: musiccommon.h:141
SearchView::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: searchview.cpp:212
MythUIButtonList::GetItemAt
MythUIButtonListItem * GetItemAt(int pos) const
Definition: mythuibuttonlist.cpp:1700
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:812
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:1947
gPlayer
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
SearchView::fieldSelected
void fieldSelected(MythUIButtonListItem *item)
Definition: searchview.cpp:328
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1614
mythuitext.h
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:51
SearchView::criteriaChanged
void criteriaChanged(void)
Definition: searchview.cpp:333
mythdb.h
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3613
MusicCommon::CreateCommon
bool CreateCommon(void)
Definition: musiccommon.cpp:78
MusicPlayerEvent
Definition: musicplayer.h:20
MusicCommon::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: musiccommon.cpp:587
MusicCommon::playlistItemClicked
void playlistItemClicked(MythUIButtonListItem *item)
Definition: musiccommon.cpp:2047
MusicCommon::createSubMenu
MythMenu * createSubMenu(void)
Definition: musiccommon.cpp:2319
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
MusicPlayer::getPlayNow
static bool getPlayNow(void)
Definition: musicplayer.cpp:230
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:217
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
MusicCommon::showTrackInfo
static void showTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:2029
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:1637
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:1679
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:111
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
MusicCommon::m_moveTrackMode
bool m_moveTrackMode
Definition: musiccommon.h:152
mythlogging.h
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:1111
MusicMetadata::toMap
void toMap(InfoMap &metadataMap, const QString &prefix="")
Definition: musicmetadata.cpp:1103
Playlist::removeTrack
void removeTrack(MusicMetadata::IdType trackID)
Definition: playlist.cpp:119
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:116
SearchView::m_fieldList
MythUIButtonList * m_fieldList
Definition: searchview.h:43
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:165
menu
static MythThemedMenu * menu
Definition: mythtv-setup.cpp:58
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1277
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:204
SearchView::SearchView
SearchView(MythScreenStack *parent, MythScreenType *parentScreen)
Definition: searchview.cpp:20
Playlist::addTrack
void addTrack(MusicMetadata::IdType trackID, bool update_display)
Given a tracks ID, add that track to this playlist.
Definition: playlist.cpp:63
MusicCommon::m_currentPlaylist
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:205
SearchView::trackClicked
static void trackClicked(MythUIButtonListItem *item)
Definition: searchview.cpp:460
SearchView::Create
bool Create(void) override
Definition: searchview.cpp:26
MusicPlayerEvent::m_trackID
int m_trackID
Definition: musicplayer.h:33
SearchView::ShowMenu
void ShowMenu(void) override
Definition: searchview.cpp:274
Playlist::checkTrack
bool checkTrack(MusicMetadata::IdType trackID) const
Definition: playlist.cpp:38
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1651
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:3338
musiccommon.h
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:23
MusicMetadata::IdType
uint32_t IdType
Definition: musicmetadata.h:86
MythMenu
Definition: mythdialogbox.h:98
mythuitextedit.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:701
MythUIButtonListItem::SetImage
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
Definition: mythuibuttonlist.cpp:3479
MusicCommon::searchButtonList
void searchButtonList(void)
Definition: musiccommon.cpp:2252
SearchView::customEvent
void customEvent(QEvent *event) override
Definition: searchview.cpp:82
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:40
SearchView::m_tracksList
MythUIButtonList * m_tracksList
Definition: searchview.h:46
SearchView::trackVisible
static void trackVisible(MythUIButtonListItem *item)
Definition: searchview.cpp:475
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
DialogCompletionEvent::kEventType
static const Type kEventType
Definition: mythdialogbox.h:56
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:1581
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:322
MythUITextEdit::valueChanged
void valueChanged()
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:52
MusicPlayerEvent::kTrackAddedEvent
static const Type kTrackAddedEvent
Definition: musicplayer.h:41
MV_SEARCH
@ MV_SEARCH
Definition: musiccommon.h:38
MythUIButtonListItem::GetImageFilename
QString GetImageFilename(const QString &name="") const
Definition: mythuibuttonlist.cpp:3573
MusicPlayer::setPlayNow
static void setPlayNow(bool PlayNow)
whether we prefer Play Now over Add Tracks
Definition: musicplayer.cpp:226
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MusicCommon::customEvent
void customEvent(QEvent *event) override
Definition: musiccommon.cpp:1232
SearchView::updateTracksList
void updateTracksList(void)
Definition: searchview.cpp:338
MusicCommon
Definition: musiccommon.h:49
MusicCommon::ShowMenu
void ShowMenu(void) override
Definition: musiccommon.cpp:2263
uint
unsigned int uint
Definition: freesurround.h:24
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837