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 // myth
8 #include <mythdialogbox.h>
9 #include <mythuitextedit.h>
10 #include <mythuibuttonlist.h>
11 #include <mythuitext.h>
12 #include <mythdb.h>
13 
14 // mythmusic
15 #include "musicdata.h"
16 #include "musiccommon.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 
65  connect(m_fieldList, SIGNAL(itemSelected(MythUIButtonListItem*)),
66  this, SLOT(fieldSelected(MythUIButtonListItem*)));
67 
68  connect(m_tracksList, SIGNAL(itemClicked(MythUIButtonListItem*)),
69  this, SLOT(trackClicked(MythUIButtonListItem*)));
70 
71  connect(m_tracksList, SIGNAL(itemVisible(MythUIButtonListItem*)),
72  this, SLOT(trackVisible(MythUIButtonListItem*)));
73 
74  connect(m_criteriaEdit, SIGNAL(valueChanged()), this, SLOT(criteriaChanged()));
75 
77 
78  return true;
79 }
80 
81 void SearchView::customEvent(QEvent *event)
82 {
83  bool handled = false;
84 
85  if (event->type() == MusicPlayerEvent::TrackRemovedEvent ||
86  event->type() == MusicPlayerEvent::TrackAddedEvent)
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)
113  {
114  m_playTrack = false;
115 
116  if (event->type() == MusicPlayerEvent::TrackAddedEvent)
117  {
118  // make the added track current and play it
121  }
122  }
123  }
124  else if (event->type() == MusicPlayerEvent::AllTracksRemovedEvent)
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::MetadataChangedEvent)
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 = false;
177  trackClicked(item);
178  }
179  }
180  }
181  else if (resulttext == tr("Add To Playlist And Play"))
182  {
183  if (GetFocusWidget() == m_tracksList)
184  {
186  if (item)
187  {
188  m_playTrack = true;
189  trackClicked(item);
190  }
191  }
192  }
193  else if (resulttext == tr("Search List..."))
195  }
196  }
197 
198  if (!handled)
200 }
201 
202 bool SearchView::keyPressEvent(QKeyEvent *event)
203 {
205  return true;
206 
207  QStringList actions;
208  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
209 
210  for (int i = 0; i < actions.size() && !handled; i++)
211  {
212  QString action = actions[i];
213  handled = true;
214 
215  if (action == "INFO" || action == "EDIT")
216  {
217  if (GetFocusWidget() == m_tracksList)
218  {
220  {
221  auto *mdata = m_tracksList->GetItemCurrent()->GetData().value<MusicMetadata*>();
222  if (mdata)
223  {
224  if (action == "INFO")
225  showTrackInfo(mdata);
226  else
227  editTrackInfo(mdata);
228  }
229  }
230  }
231  else
232  handled = false;
233  }
234  else if (action == "PLAY")
235  {
236  if (GetFocusWidget() == m_tracksList)
237  {
239  if (item)
240  {
241  m_playTrack = true;
242  trackClicked(item);
243  }
244  }
245  else
246  handled = false;
247  }
248  else
249  handled = false;
250  }
251 
252  if (!handled && MusicCommon::keyPressEvent(event))
253  handled = true;
254 
255  return handled;
256 }
257 
259 {
260  if (GetFocusWidget() == m_tracksList)
261  {
262  QString label = tr("Search Actions");
263 
264  auto *menu = new MythMenu(label, this, "searchviewmenu");
265 
267  if (item)
268  {
269  auto *mdata = item->GetData().value<MusicMetadata*>();
270  if (mdata)
271  {
273  menu->AddItem(tr("Remove From Playlist"));
274  else
275  {
276  menu->AddItem(tr("Add To Playlist"));
277  menu->AddItem(tr("Add To Playlist And Play"));
278  }
279  }
280  }
281 
283  menu->AddItem(tr("Search List..."));
284 
285  menu->AddItem(tr("More Options"), nullptr, createSubMenu());
286 
287  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
288 
289  auto *menuPopup = new MythDialogBox(menu, popupStack, "actionmenu");
290 
291  if (menuPopup->Create())
292  popupStack->AddScreen(menuPopup);
293  else
294  delete menu;
295  }
296  else
298 }
299 
301 {
302  (void) item;
304 }
305 
307 {
309 }
310 
312 {
313  m_tracksList->Reset();
314 
316 
317  if (!item)
318  return;
319 
320  QString searchStr = m_criteriaEdit->GetText();
321  int field = item->GetData().toInt();
322 
323  QString sql;
325 
326  if (searchStr.isEmpty())
327  {
328  sql = "SELECT song_id "
329  "FROM music_songs ";
330 
331  query.prepare(sql);
332  }
333  else
334  {
335  switch(field)
336  {
337  case 1: // artist
338  {
339  sql = "SELECT song_id "
340  "FROM music_songs "
341  "LEFT JOIN music_artists ON "
342  " music_songs.artist_id=music_artists.artist_id "
343  "WHERE music_artists.artist_name LIKE '%" + searchStr + "%' ";
344  query.prepare(sql);
345  break;
346  }
347  case 2: // album
348  {
349  sql = "SELECT song_id "
350  "FROM music_songs "
351  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
352  "WHERE music_albums.album_name LIKE '%" + searchStr + "%' ";
353  query.prepare(sql);
354  break;
355  }
356  case 3: // title
357  {
358  sql = "SELECT song_id "
359  "FROM music_songs "
360  "WHERE music_songs.name LIKE '%" + searchStr + "%' ";
361  query.prepare(sql);
362  break;
363  }
364  case 4: // genre
365  {
366  sql = "SELECT song_id "
367  "FROM music_songs "
368  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
369  "WHERE music_genres.genre LIKE '%" + searchStr + "%' ";
370  query.prepare(sql);
371  break;
372  }
373  case 5: // tags
374  {
375  //TODO add tag query. Remove fallthrough once added.
376  [[clang::fallthrough]];
377  }
378  case 0: // all fields
379  default:
380  {
381  sql = "SELECT song_id "
382  "FROM music_songs "
383  "LEFT JOIN music_artists ON "
384  " music_songs.artist_id=music_artists.artist_id "
385  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
386  "LEFT JOIN music_artists AS music_comp_artists ON "
387  " music_albums.artist_id=music_comp_artists.artist_id "
388  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
389  "WHERE music_songs.name LIKE '%" + searchStr + "%' "
390  "OR music_artists.artist_name LIKE '%" + searchStr + "%' "
391  "OR music_albums.album_name LIKE '%" + searchStr + "%' "
392  "OR music_genres.genre LIKE '%" + searchStr + "%' ";
393 
394  query.prepare(sql);
395  }
396  }
397  }
398 
399  if (!query.exec() || !query.isActive())
400  {
401  MythDB::DBError("Search music database", query);
402  return;
403  }
404 
405  while (query.next())
406  {
407  int trackid = query.value(0).toInt();
408 
409  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackid);
410  if (mdata)
411  {
412  auto *newitem = new MythUIButtonListItem(m_tracksList, "");
413  newitem->SetData(QVariant::fromValue(mdata));
414  InfoMap metadataMap;
415  mdata->toMap(metadataMap);
416  newitem->SetTextFromMap(metadataMap);
417 
419  newitem->DisplayState("on", "selectedstate");
420  else
421  newitem->DisplayState("off", "selectedstate");
422 
423  // TODO rating state etc
424  }
425  }
426 
428 
429  if (m_matchesText)
430  m_matchesText->SetText(QString("%1").arg(m_tracksList->GetCount()));
431 }
432 
434 {
435  if (!gPlayer->getCurrentPlaylist())
436  return;
437 
438  auto *mdata = item->GetData().value<MusicMetadata*>();
439  if (mdata)
440  {
441  if (gPlayer->getCurrentPlaylist()->checkTrack(mdata->ID()))
442  gPlayer->getCurrentPlaylist()->removeTrack(mdata->ID());
443  else
444  gPlayer->getCurrentPlaylist()->addTrack(mdata->ID(), true);
445  }
446 }
447 
449 {
450 
451  if (!item)
452  return;
453 
454  if (item->GetImageFilename().isEmpty())
455  {
456  auto *mdata = item->GetData().value<MusicMetadata*>();
457  if (mdata)
458  {
459  QString artFile = mdata->getAlbumArtFile();
460  if (artFile.isEmpty())
461  item->SetImage("");
462  else
463  item->SetImage(mdata->getAlbumArtFile());
464  }
465  else
466  item->SetImage("");
467  }
468 }
MusicCommon::m_currentView
MusicView m_currentView
Definition: musiccommon.h:139
SearchView::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: searchview.cpp:202
MythUIButtonList::GetItemAt
MythUIButtonListItem * GetItemAt(int pos) const
Definition: mythuibuttonlist.cpp:1676
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:204
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
MusicCommon::editTrackInfo
static void editTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:1868
gPlayer
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
SearchView::fieldSelected
void fieldSelected(MythUIButtonListItem *item)
Definition: searchview.cpp:300
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1590
mythuitext.h
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:52
SearchView::criteriaChanged
void criteriaChanged(void)
Definition: searchview.cpp:306
mythdb.h
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3507
MusicCommon::CreateCommon
bool CreateCommon(void)
Definition: musiccommon.cpp:81
MusicPlayerEvent
Definition: musicplayer.h:21
MusicCommon::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: musiccommon.cpp:581
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1106
MusicCommon::playlistItemClicked
void playlistItemClicked(MythUIButtonListItem *item)
Definition: musiccommon.cpp:1966
DialogCompletionEvent::kEventType
static Type kEventType
Definition: mythdialogbox.h:57
MusicCommon::createSubMenu
MythMenu * createSubMenu(void)
Definition: musiccommon.cpp:2213
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
MythScreenStack
Definition: mythscreenstack.h:15
arg
arg(title).arg(filename).arg(doDelete))
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:603
MusicPlayerEvent::TrackAddedEvent
static Type TrackAddedEvent
Definition: musicplayer.h:42
MusicCommon::showTrackInfo
static void showTrackInfo(MusicMetadata *mdata)
Definition: musiccommon.cpp:1948
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:44
MusicMetadata
Definition: musicmetadata.h:80
MusicPlayerEvent::MetadataChangedEvent
static Type MetadataChangedEvent
Definition: musicplayer.h:46
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:47
MusicPlayer::getCurrentPlaylist
Playlist * getCurrentPlaylist(void)
Definition: musicplayer.cpp:1595
SearchView::m_matchesText
MythUIText * m_matchesText
Definition: searchview.h:45
menu
static MythThemedMenu * menu
Definition: mythtv/programs/mythtv-setup/main.cpp:55
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &stackname)
Definition: mythmainwindow.cpp:309
mythuibuttonlist.h
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1655
SearchView::m_criteriaEdit
MythUITextEdit * m_criteriaEdit
Definition: searchview.h:44
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:112
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MythUIButtonListItem
Definition: mythuibuttonlist.h:27
MusicCommon::m_moveTrackMode
bool m_moveTrackMode
Definition: musiccommon.h:150
SearchView::m_playTrack
bool m_playTrack
Definition: searchview.h:42
MusicMetadata::toMap
void toMap(InfoMap &metadataMap, const QString &prefix="")
Definition: musicmetadata.cpp:1099
Playlist::removeTrack
void removeTrack(MusicMetadata::IdType trackID)
Definition: playlist.cpp:117
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:117
SearchView::m_fieldList
MythUIButtonList * m_fieldList
Definition: searchview.h:43
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:137
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1270
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
searchview.h
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:222
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:63
MusicCommon::m_currentPlaylist
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:203
SearchView::trackClicked
static void trackClicked(MythUIButtonListItem *item)
Definition: searchview.cpp:433
SearchView::Create
bool Create(void) override
Definition: searchview.cpp:25
MusicPlayerEvent::m_trackID
int m_trackID
Definition: musicplayer.h:34
SearchView::ShowMenu
void ShowMenu(void) override
Definition: searchview.cpp:258
Playlist::checkTrack
bool checkTrack(MusicMetadata::IdType trackID) const
Definition: playlist.cpp:38
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3588
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1647
uint
unsigned int uint
Definition: compat.h:140
MusicPlayerEvent::AllTracksRemovedEvent
static Type AllTracksRemovedEvent
Definition: musicplayer.h:45
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:3289
musiccommon.h
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:20
MusicMetadata::IdType
uint32_t IdType
Definition: musicmetadata.h:86
MythMenu
Definition: mythdialogbox.h:92
mythuitextedit.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:692
MythUIButtonListItem::SetImage
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
Definition: mythuibuttonlist.cpp:3406
MusicCommon::searchButtonList
void searchButtonList(void)
Definition: musiccommon.cpp:2153
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
MusicPlayerEvent::TrackRemovedEvent
static Type TrackRemovedEvent
Definition: musicplayer.h:43
SearchView::trackVisible
static void trackVisible(MythUIButtonListItem *item)
Definition: searchview.cpp:448
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:113
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:107
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1557
build_compdb.action
action
Definition: build_compdb.py:9
MV_SEARCH
@ MV_SEARCH
Definition: musiccommon.h:37
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:55
MythUIButtonListItem::GetImageFilename
QString GetImageFilename(const QString &name="") const
Definition: mythuibuttonlist.cpp:3494
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:49
query
MSqlQuery query(MSqlQuery::InitCon())
MusicCommon::customEvent
void customEvent(QEvent *event) override
Definition: musiccommon.cpp:1186
SearchView::updateTracksList
void updateTracksList(void)
Definition: searchview.cpp:311
MusicCommon
Definition: musiccommon.h:47
MusicCommon::ShowMenu
void ShowMenu(void) override
Definition: musiccommon.cpp:2164
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808