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
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
82void SearchView::customEvent(QEvent *event)
83{
84 bool handled = false;
85
86 if (event->type() == MusicPlayerEvent::kTrackRemovedEvent ||
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 {
172 {
174 if (item)
175 {
176 m_playTrack = 0;
177 trackClicked(item);
178 }
179 }
180 }
181 else if (resulttext == tr("Play Now"))
182 {
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
212bool 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 {
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 {
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{
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{
341
343
344 if (!item)
345 return;
346
347 QString searchStr = m_criteriaEdit->GetText();
348 int field = item->GetData().toInt();
349
350 QString sql;
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
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{
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}
MusicMetadata * getMetadata(int an_id)
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
static const Type kEventType
Definition: mythdialogbox.h:56
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
bool m_moveTrackMode
Definition: musiccommon.h:152
void playlistItemClicked(MythUIButtonListItem *item)
static void showTrackInfo(MusicMetadata *mdata)
MusicView m_currentView
Definition: musiccommon.h:141
void ShowMenu(void) override
bool CreateCommon(void)
Definition: musiccommon.cpp:78
static void editTrackInfo(MusicMetadata *mdata)
MythMenu * createSubMenu(void)
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
void searchButtonList(void)
void customEvent(QEvent *event) override
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:205
AllMusic * m_all_music
Definition: musicdata.h:52
void toMap(InfoMap &metadataMap, const QString &prefix="")
QString getAlbumArtFile(void)
IdType ID() const
uint32_t IdType
Definition: musicmetadata.h:91
static const Type kMetadataChangedEvent
Definition: musicplayer.h:45
static const Type kAllTracksRemovedEvent
Definition: musicplayer.h:44
static const Type kTrackAddedEvent
Definition: musicplayer.h:41
static const Type kTrackRemovedEvent
Definition: musicplayer.h:42
static bool getPlayNow(void)
Playlist * getCurrentPlaylist(void)
static void setPlayNow(bool PlayNow)
whether we prefer Play Now over Add Tracks
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
Basic menu dialog, message and a list of options.
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool SetFocusWidget(MythUIType *widget=nullptr)
void DisplayState(const QString &state, const QString &name)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
QString GetImageFilename(const QString &name="") const
MythUIButtonListItem * GetItemCurrent() const
void itemVisible(MythUIButtonListItem *item)
void SetItemCurrent(MythUIButtonListItem *item)
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
void itemClicked(MythUIButtonListItem *item)
MythUIButtonListItem * GetItemAt(int pos) const
void itemSelected(MythUIButtonListItem *item)
QString GetText(void) const
void valueChanged()
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
void removeTrack(MusicMetadata::IdType trackID)
Definition: playlist.cpp:119
void addTrack(MusicMetadata::IdType trackID, bool update_display)
Given a tracks ID, add that track to this playlist.
Definition: playlist.cpp:63
bool checkTrack(MusicMetadata::IdType trackID) const
Definition: playlist.cpp:38
SearchView(MythScreenStack *parent, MythScreenType *parentScreen)
Definition: searchview.cpp:20
void updateTracksList(void)
Definition: searchview.cpp:338
static void trackVisible(MythUIButtonListItem *item)
Definition: searchview.cpp:475
MythUIText * m_matchesText
Definition: searchview.h:45
bool Create(void) override
Definition: searchview.cpp:26
MythUIButtonList * m_tracksList
Definition: searchview.h:46
void customEvent(QEvent *event) override
Definition: searchview.cpp:82
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: searchview.cpp:212
void criteriaChanged(void)
Definition: searchview.cpp:333
void fieldSelected(MythUIButtonListItem *item)
Definition: searchview.cpp:328
static void trackClicked(MythUIButtonListItem *item)
Definition: searchview.cpp:460
MythUITextEdit * m_criteriaEdit
Definition: searchview.h:44
MythUIButtonList * m_fieldList
Definition: searchview.h:43
int m_playTrack
Definition: searchview.h:42
void ShowMenu(void) override
Definition: searchview.cpp:274
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
unsigned int uint
Definition: freesurround.h:24
@ MV_SEARCH
Definition: musiccommon.h:38
MusicData * gMusicData
Definition: musicdata.cpp:23
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
static MythThemedMenu * menu
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27