MythTV  master
smartplaylist.cpp
Go to the documentation of this file.
1 // c/c++
2 #include <iostream>
3 #include <unistd.h>
4 #include <utility>
5 
6 // qt
7 #include <QKeyEvent>
8 #include <QSqlDriver>
9 #include <QSqlField>
10 
11 // MythTV
12 #include <libmyth/mythcontext.h>
13 #include <libmythbase/mythdate.h>
14 #include <libmythbase/mythdb.h>
19 #include <libmythui/mythuibutton.h>
22 #include <libmythui/mythuihelper.h>
24 #include <libmythui/mythuitext.h>
26 
27 // mythmusic
28 #include "musiccommon.h"
29 #include "musicdata.h"
30 #include "smartplaylist.h"
31 
33 {
34  QString m_name;
35  QString m_sqlName;
40 };
41 
42 static const std::array<const SmartPLField,13> SmartPLFields
43 {{
44  { "", "", ftString, 0, 0, 0 },
45  { "Artist", "music_artists.artist_name", ftString, 0, 0, 0 },
46  { "Album", "music_albums.album_name", ftString, 0, 0, 0 },
47  { "Title", "music_songs.name", ftString, 0, 0, 0 },
48  { "Genre", "music_genres.genre", ftString, 0, 0, 0 },
49  { "Year", "music_songs.year", ftNumeric, 1900, 2099, 2000 },
50  { "Track No.", "music_songs.track", ftNumeric, 0, 99, 0 },
51  { "Rating", "music_songs.rating", ftNumeric, 0, 10, 0 },
52  { "Play Count", "music_songs.numplays", ftNumeric, 0, 9999, 0 },
53  { "Compilation", "music_albums.compilation", ftBoolean, 0, 0, 0 },
54  { "Comp. Artist", "music_comp_artists.artist_name", ftString, 0, 0, 0 },
55  { "Last Play", "FROM_DAYS(TO_DAYS(music_songs.lastplay))",
56  ftDate, 0, 0, 0 },
57  { "Date Imported", "FROM_DAYS(TO_DAYS(music_songs.date_entered))",
58  ftDate, 0, 0, 0 },
59 }};
60 
62 {
63  QString m_name;
67 };
68 
69 static const std::array<const SmartPLOperator,11> SmartPLOperators
70 {{
71  { "is equal to", 1, false, true },
72  { "is not equal to", 1, false, true },
73  { "is greater than", 1, false, false },
74  { "is less than", 1, false, false },
75  { "starts with", 1, true, false },
76  { "ends with", 1, true, false },
77  { "contains", 1, true, false },
78  { "does not contain", 1, true, false },
79  { "is between", 2, false, false },
80  { "is set", 0, false, false },
81  { "is not set", 0, false, false },
82 }};
83 
84 static const SmartPLOperator *lookupOperator(const QString& name)
85 {
86  for (const auto & oper : SmartPLOperators)
87  {
88  if (oper.m_name == name)
89  return &oper;
90  }
91  return nullptr;
92 }
93 
94 static const SmartPLField *lookupField(const QString& name)
95 {
96  for (const auto & field : SmartPLFields)
97  {
98  if (field.m_name == name)
99  return &field;
100  }
101  return nullptr;
102 }
103 
104 QString formattedFieldValue(const QVariant &value)
105 {
106 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
107  QSqlField field("", value.type());
108 #else
109  QSqlField field("", value.metaType());
110 #endif
111  if (value.isNull())
112  field.clear();
113  else
114  field.setValue(value);
115 
116  MSqlQuery query(MSqlQuery::InitCon());
117  QString result = QString::fromUtf8(query.driver()->formatValue(field).toLatin1().data());
118  return result;
119 }
120 
121 static QString evaluateDateValue(QString sDate)
122 {
123  if (sDate.startsWith("$DATE"))
124  {
125  QDate date = MythDate::current().toLocalTime().date();
126 
127  if (sDate.length() > 9)
128  {
129  bool bNegative = false;
130  if (sDate[6] == '-')
131  bNegative = true;
132 
133  if (sDate.endsWith(" days"))
134  sDate = sDate.left(sDate.length() - 5);
135 
136  int nDays = sDate.mid(8).toInt();
137  if (bNegative)
138  nDays = -nDays;
139 
140  date = date.addDays(nDays);
141  }
142 
143  return date.toString(Qt::ISODate);
144  }
145 
146  return sDate;
147 }
148 
149 QString getCriteriaSQL(const QString& fieldName, const QString &operatorName,
150  QString value1, QString value2)
151 {
152  QString result;
153 
154  if (fieldName.isEmpty())
155  return result;
156 
157  const SmartPLField *Field = lookupField(fieldName);
158  if (!Field)
159  {
160  return "";
161  }
162 
163  result = Field->m_sqlName;
164 
165  const SmartPLOperator *Operator = lookupOperator(operatorName);
166  if (!Operator)
167  {
168  return {};
169  }
170 
171  // convert boolean and date values
172  if (Field->m_type == ftBoolean)
173  {
174  // compilation field uses 0 = false; 1 = true
175  value1 = (value1 == "Yes") ? "1":"0";
176  value2 = (value2 == "Yes") ? "1":"0";
177  }
178  else if (Field->m_type == ftDate)
179  {
180  value1 = evaluateDateValue(value1);
181  value2 = evaluateDateValue(value2);
182  }
183 
184  if (Operator->m_name == "is equal to")
185  {
186  result = result + " = " + formattedFieldValue(value1);
187  }
188  else if (Operator->m_name == "is not equal to")
189  {
190  result = result + " != " + formattedFieldValue(value1);
191  }
192  else if (Operator->m_name == "is greater than")
193  {
194  result = result + " > " + formattedFieldValue(value1);
195  }
196  else if (Operator->m_name == "is less than")
197  {
198  result = result + " < " + formattedFieldValue(value1);
199  }
200  else if (Operator->m_name == "starts with")
201  {
202  result = result + " LIKE " + formattedFieldValue(value1 + QString("%"));
203  }
204  else if (Operator->m_name == "ends with")
205  {
206  result = result + " LIKE " + formattedFieldValue(QString("%") + value1);
207  }
208  else if (Operator->m_name == "contains")
209  {
210  result = result + " LIKE " + formattedFieldValue(QString("%") + value1 + "%");
211  }
212  else if (Operator->m_name == "does not contain")
213  {
214  result = result + " NOT LIKE " + formattedFieldValue(QString("%") + value1 + "%");
215  }
216  else if (Operator->m_name == "is between")
217  {
218  result = result + " BETWEEN " + formattedFieldValue(value1) +
219  " AND " + formattedFieldValue(value2);
220  }
221  else if (Operator->m_name == "is set")
222  {
223  result = result + " IS NOT NULL";
224  }
225  else if (Operator->m_name == "is not set")
226  {
227  result = result + " IS NULL";
228  }
229  else
230  {
231  result.clear();
232  LOG(VB_GENERAL, LOG_ERR,
233  QString("getCriteriaSQL(): invalid operator '%1'")
234  .arg(Operator->m_name));
235  }
236 
237  return result;
238 }
239 
240 QString getOrderBySQL(const QString& orderByFields)
241 {
242  if (orderByFields.isEmpty())
243  return {};
244 
245  QStringList list = orderByFields.split(",");
246  QString fieldName;
247  QString result;
248  QString order;
249  bool bFirst = true;
250 
251  for (int x = 0; x < list.count(); x++)
252  {
253  fieldName = list[x].trimmed();
254  const SmartPLField *Field = lookupField(fieldName.left(fieldName.length() - 4));
255  if (Field)
256  {
257  if (fieldName.right(3) == "(D)")
258  order = " DESC";
259  else
260  order = " ASC";
261 
262  if (bFirst)
263  {
264  bFirst = false;
265  result = " ORDER BY " + Field->m_sqlName + order;
266  }
267  else
268  {
269  result += ", " + Field->m_sqlName + order;
270  }
271  }
272  }
273 
274  return result;
275 }
276 
277 QString getSQLFieldName(const QString &fieldName)
278 {
279  const SmartPLField *Field = lookupField(fieldName);
280  if (!Field)
281  {
282  return "";
283  }
284 
285  return Field->m_sqlName;
286 }
287 
288 /*
290 */
291 
292 QString SmartPLCriteriaRow::getSQL(void) const
293 {
294  if (m_field.isEmpty())
295  return {};
296 
297  QString result;
298 
300 
301  return result;
302 }
303 
304 // return false on error
305 bool SmartPLCriteriaRow::saveToDatabase(int smartPlaylistID) const
306 {
307  // save playlistitem to database
308 
309  if (m_field.isEmpty())
310  return true;
311 
312  MSqlQuery query(MSqlQuery::InitCon());
313  query.prepare("INSERT INTO music_smartplaylist_items (smartplaylistid, field, operator,"
314  " value1, value2)"
315  "VALUES (:SMARTPLAYLISTID, :FIELD, :OPERATOR, :VALUE1, :VALUE2);");
316  query.bindValue(":SMARTPLAYLISTID", smartPlaylistID);
317  query.bindValueNoNull(":FIELD", m_field);
318  query.bindValueNoNull(":OPERATOR", m_operator);
319  query.bindValueNoNull(":VALUE1", m_value1);
320  query.bindValueNoNull(":VALUE2", m_value2);
321 
322  if (!query.exec())
323  {
324  MythDB::DBError("Inserting new smartplaylist item", query);
325  return false;
326  }
327 
328  return true;
329 }
330 
331 QString SmartPLCriteriaRow::toString(void) const
332 {
333  const SmartPLOperator *PLOperator = lookupOperator(m_operator);
334  if (PLOperator)
335  {
336  QString result;
337  if (PLOperator->m_noOfArguments == 0)
338  result = m_field + " " + m_operator;
339  else if (PLOperator->m_noOfArguments == 1)
340  result = m_field + " " + m_operator + " " + m_value1;
341  else
342  {
343  result = m_field + " " + m_operator + " " + m_value1;
344  result += " " + tr("and") + " " + m_value2;
345  }
346 
347  return result;
348  }
349 
350  return {};
351 }
352 
353 /*
354 ---------------------------------------------------------------------
355 */
356 
358 {
359  while (!m_criteriaRows.empty())
360  {
361  delete m_criteriaRows.back();
362  m_criteriaRows.pop_back();
363  }
364 
365  delete m_tempCriteriaRow;
366 }
367 
368 
370 {
371  if (!LoadWindowFromXML("music-ui.xml", "smartplaylisteditor", this))
372  return false;
373 
374  bool err = false;
375 
376  UIUtilE::Assign(this, m_categorySelector, "categoryselector", &err);
377  UIUtilE::Assign(this, m_categoryButton, "categorybutton", &err);
378  UIUtilE::Assign(this, m_titleEdit, "titleedit", &err);
379  UIUtilE::Assign(this, m_matchSelector, "matchselector", &err);
380  UIUtilE::Assign(this, m_criteriaList, "criterialist", &err);
381  UIUtilE::Assign(this, m_orderBySelector, "orderbyselector", &err);
382  UIUtilE::Assign(this, m_orderByButton, "orderbybutton", &err);
383  UIUtilE::Assign(this, m_matchesText, "matchestext", &err);
384  UIUtilE::Assign(this, m_limitSpin, "limitspin", &err);
385 
386  UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
387  UIUtilE::Assign(this, m_saveButton, "savebutton", &err);
388  UIUtilE::Assign(this, m_showResultsButton, "showresultsbutton", &err);
389 
390  if (err)
391  {
392  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'smartplaylisteditor'");
393  return false;
394  }
395 
397 
398  new MythUIButtonListItem(m_matchSelector, tr("All"));
399  new MythUIButtonListItem(m_matchSelector, tr("Any"));
401 
402  for (const auto & field : SmartPLFields)
403  {
404  if (field.m_name == "")
405  new MythUIButtonListItem(m_orderBySelector, field.m_name);
406  else
407  new MythUIButtonListItem(m_orderBySelector, field.m_name + " (A)");
408  }
409 
410  m_limitSpin->SetRange(0, 9999, 10);
411 
418 
419  BuildFocusList();
420 
421  return true;
422 }
423 
425 {
426  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
427  return true;
428 
429  QStringList actions;
430  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
431 
432  for (int i = 0; i < actions.size() && !handled; i++)
433  {
434  const QString& action = actions[i];
435  handled = true;
436 
437  if (action == "MENU")
438  {
440  }
441  else if (action == "DELETE" && GetFocusWidget() == m_criteriaList)
442  {
443  deleteCriteria();
444  }
445  else if (action == "EDIT" && GetFocusWidget() == m_criteriaList)
446  {
447  editCriteria();
448  }
449  else
450  {
451  handled = false;
452  }
453  }
454 
455  if (!handled && MythScreenType::keyPressEvent(event))
456  handled = true;
457 
458  return handled;
459 }
460 
462 {
463  if (auto *dce = dynamic_cast<DialogCompletionEvent*>(event))
464  {
465  // make sure the user didn't ESCAPE out of the menu
466  if (dce->GetResult() < 0)
467  return;
468 
469  QString resultid = dce->GetId();
470  QString resulttext = dce->GetResultText();
471  if (resultid == "categorymenu")
472  {
473  if (resulttext == tr("New Category"))
474  {
475  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
476  QString label = tr("Enter Name Of New Category");
477 
478  auto *input = new MythTextInputDialog(popupStack, label);
479 
480  connect(input, &MythTextInputDialog::haveResult,
482 
483  if (input->Create())
484  popupStack->AddScreen(input);
485  else
486  delete input;
487  }
488  else if (resulttext == tr("Delete Category"))
489  {
491  }
492  else if (resulttext == tr("Rename Category"))
493  {
494  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
495  QString label = tr("Enter New Name For Category: %1").arg(m_categorySelector->GetValue());
496 
497  auto *input = new MythTextInputDialog(popupStack, label);
498 
499  connect(input, &MythTextInputDialog::haveResult,
501 
502  if (input->Create())
503  popupStack->AddScreen(input);
504  else
505  delete input;
506  }
507  }
508  }
509 }
510 
512 {
513  if (m_tempCriteriaRow)
514  {
515  delete m_tempCriteriaRow;
516  m_tempCriteriaRow = nullptr;
517  }
518 
520 
521  if (!item)
522  return;
523 
524  auto *row = item->GetData().value<SmartPLCriteriaRow*>();
525 
526  if (!row)
527  return;
528 
529  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
530 
531  auto *editor = new CriteriaRowEditor(popupStack, row);
532 
533  if (!editor->Create())
534  {
535  delete editor;
536  return;
537  }
538 
540 
541  popupStack->AddScreen(editor);
542 }
543 
545 {
546  // make sure we have something to delete
548 
549  if (!item)
550  return;
551 
552  ShowOkPopup(tr("Delete Criteria?"), this, &SmartPlaylistEditor::doDeleteCriteria, true);
553 }
554 
556 {
557  if (doit)
558  {
560  if (!item)
561  return;
562 
563  auto *row = item->GetData().value<SmartPLCriteriaRow*>();
564 
565  if (!row)
566  return;
567 
568  m_criteriaRows.removeAll(row);
569  m_criteriaList->RemoveItem(item);
570 
571  criteriaChanged();
572  }
573 }
574 
576 {
577  /*
578  SmartPLCriteriaRow *row = new SmartPLCriteriaRow();
579  m_criteriaRows.append(row);
580 
581  MythUIButtonListItem *item = new MythUIButtonListItem(m_criteriaList, row->toString(), QVariant::fromValue(row));
582 
583  m_criteriaList->SetItemCurrent(item);
584 
585  editCriteria();
586  */
587 
588  delete m_tempCriteriaRow;
590 
591  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
592 
593  auto *editor = new CriteriaRowEditor(popupStack, m_tempCriteriaRow);
594 
595  if (!editor->Create())
596  {
597  delete editor;
598  return;
599  }
600 
602 
603  popupStack->AddScreen(editor);
604 }
605 
607 {
608  MythUIButtonListItem *item = nullptr;
609 
610  if (m_tempCriteriaRow)
611  {
612  // this is a new row so add it to the list
614 
616  QVariant::fromValue(m_tempCriteriaRow));
617 
619 
620  m_tempCriteriaRow = nullptr;
621  }
622  else
623  {
624  // update the existing row
625  item = m_criteriaList->GetItemCurrent();
626  if (!item)
627  return;
628 
629  auto *row = item->GetData().value<SmartPLCriteriaRow*>();
630 
631  if (!row)
632  return;
633 
634  item->SetText(row->toString());
635  }
636 
637  updateMatches();
638 }
639 
641 {
642  QString label = tr("Category Actions");
643 
644  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
645 
646  auto *menu = new MythDialogBox(label, popupStack, "actionmenu");
647 
648  if (!menu->Create())
649  {
650  delete menu;
651  return;
652  }
653 
654  menu->SetReturnEvent(this, "categorymenu");
655 
656  menu->AddButton(tr("New Category"), nullptr);
657  menu->AddButton(tr("Delete Category"), nullptr);
658  menu->AddButton(tr("Rename Category"), nullptr);
659 
660  popupStack->AddScreen(menu);
661 }
662 
664 {
665  QString label = tr("Criteria Actions");
666 
667  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
668 
669  auto *menu = new MythDialogBox(label, popupStack, "actionmenu");
670 
671  if (!menu->Create())
672  {
673  delete menu;
674  return;
675  }
676 
677  menu->SetReturnEvent(this, "criteriamenu");
678 
680 
681  if (item)
682  menu->AddButton(tr("Edit Criteria"), &SmartPlaylistEditor::editCriteria);
683 
684  menu->AddButton(tr("Add Criteria"), &SmartPlaylistEditor::addCriteria);
685 
686  if (item)
687  menu->AddButton(tr("Delete Criteria"), &SmartPlaylistEditor::deleteCriteria);
688 
689  popupStack->AddScreen(menu);
690 }
691 
693 {
695 }
696 
698 {
699  QString sql =
700  "SELECT count(*) "
701  "FROM music_songs "
702  "LEFT JOIN music_artists ON "
703  " music_songs.artist_id=music_artists.artist_id "
704  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
705  "LEFT JOIN music_artists AS music_comp_artists ON "
706  " music_albums.artist_id=music_comp_artists.artist_id "
707  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
708 
709  sql += getWhereClause();
710 
711  m_matchesCount = 0;
712 
713  MSqlQuery query(MSqlQuery::InitCon());
714  if (!query.exec(sql))
715  MythDB::DBError("SmartPlaylistEditor::updateMatches", query);
716  else if (query.next())
717  m_matchesCount = query.value(0).toInt();
718 
719  m_matchesText->SetText(QString::number(m_matchesCount));
720 
723  titleChanged();
724 }
725 
727 {
728  // save smartplaylist to database
729 
730  QString name = m_titleEdit->GetText();
731  QString category = m_categorySelector->GetValue();
732  QString matchType = (m_matchSelector->GetValue() == tr("All") ? "All" : "Any");
733  QString orderBy = m_orderBySelector->GetValue();
734  QString limit = m_limitSpin->GetValue();
735 
736  // lookup categoryid
737  int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
738 
739  // easier to delete any existing smartplaylist and recreate a new one
740  if (!m_newPlaylist)
742  else
744 
745  MSqlQuery query(MSqlQuery::InitCon());
746  // insert new smartplaylist
747  query.prepare("INSERT INTO music_smartplaylists (name, categoryid, matchtype, orderby, limitto) "
748  "VALUES (:NAME, :CATEGORYID, :MATCHTYPE, :ORDERBY, :LIMIT);");
749  query.bindValue(":NAME", name);
750  query.bindValue(":CATEGORYID", categoryid);
751  query.bindValue(":MATCHTYPE", matchType);
752  query.bindValue(":ORDERBY", orderBy);
753  query.bindValue(":LIMIT", limit);
754 
755  if (!query.exec())
756  {
757  MythDB::DBError("Inserting new playlist", query);
758  return;
759  }
760 
761  // get smartplaylistid
762  int ID = -1;
763  query.prepare("SELECT smartplaylistid FROM music_smartplaylists "
764  "WHERE categoryid = :CATEGORYID AND name = :NAME;");
765  query.bindValue(":CATEGORYID", categoryid);
766  query.bindValue(":NAME", name);
767  if (query.exec())
768  {
769  if (query.isActive() && query.size() > 0)
770  {
771  query.first();
772  ID = query.value(0).toInt();
773  }
774  else
775  {
776  LOG(VB_GENERAL, LOG_ERR,
777  QString("Failed to find ID for smartplaylist: %1").arg(name));
778  return;
779  }
780  }
781  else
782  {
783  MythDB::DBError("Getting smartplaylist ID", query);
784  return;
785  }
786 
787  // save smartplaylist items
788  for (const auto & row : std::as_const(m_criteriaRows))
789  row->saveToDatabase(ID);
790 
791  emit smartPLChanged(category, name);
792 
793  Close();
794 }
795 
796 void SmartPlaylistEditor::newSmartPlaylist(const QString& category)
797 {
798  m_categorySelector->SetValue(category);
799  m_titleEdit->Reset();
800  m_originalCategory = category;
801  m_originalName.clear();
802 
803  m_newPlaylist = true;
804 
805  updateMatches();
806 }
807 
808 void SmartPlaylistEditor::editSmartPlaylist(const QString& category, const QString& name)
809 {
810  m_originalCategory = category;
811  m_originalName = name;
812  m_newPlaylist = false;
813  loadFromDatabase(category, name);
814  updateMatches();
815 }
816 
817 void SmartPlaylistEditor::loadFromDatabase(const QString& category, const QString& name)
818 {
819  // load smartplaylist from database
820  int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
821 
822  MSqlQuery query(MSqlQuery::InitCon());
823  int ID = -1;
824 
825  query.prepare("SELECT smartplaylistid, name, categoryid, matchtype, orderby, limitto "
826  "FROM music_smartplaylists WHERE name = :NAME AND categoryid = :CATEGORYID;");
827  query.bindValue(":NAME", name);
828  query.bindValue(":CATEGORYID", categoryid);
829  if (query.exec())
830  {
831  if (query.isActive() && query.size() > 0)
832  {
833  query.first();
834  ID = query.value(0).toInt();
835  m_titleEdit->SetText(name);
836  m_categorySelector->SetValue(category);
837  if (query.value(3).toString() == "All")
838  m_matchSelector->SetValue(tr("All"));
839  else
840  m_matchSelector->SetValue(tr("Any"));
841 
842  QString orderBy = query.value(4).toString();
843  if (!m_orderBySelector->Find(orderBy))
844  {
845  // not found so add it to the selector
847  m_orderBySelector->SetValue(orderBy);
848  }
849 
850  m_limitSpin->SetValue(query.value(5).toInt());
851  }
852  else
853  {
854  LOG(VB_GENERAL, LOG_ERR,
855  QString("Cannot find smartplaylist: %1").arg(name));
856  return;
857  }
858  }
859  else
860  {
861  MythDB::DBError("Load smartplaylist", query);
862  return;
863  }
864 
866 
867  query.prepare("SELECT field, operator, value1, value2 "
868  "FROM music_smartplaylist_items WHERE smartplaylistid = :ID "
869  "ORDER BY smartplaylistitemid;");
870  query.bindValue(":ID", ID);
871  if (!query.exec())
872  MythDB::DBError("Load smartplaylist items", query);
873 
874  if (query.size() > 0)
875  {
876  while (query.next())
877  {
878  QString Field = query.value(0).toString();
879  QString Operator = query.value(1).toString();
880  QString Value1 = query.value(2).toString();
881  QString Value2 = query.value(3).toString();
882  // load smartplaylist items
883  auto *row = new SmartPLCriteriaRow(Field, Operator, Value1, Value2);
884  m_criteriaRows.append(row);
885 
886  new MythUIButtonListItem(m_criteriaList, row->toString(), QVariant::fromValue(row));
887  }
888  }
889  else
890  {
891  LOG(VB_GENERAL, LOG_WARNING,
892  QString("Got no smartplaylistitems for ID: ").arg(ID));
893  }
894 }
895 
896 void SmartPlaylistEditor::newCategory(const QString &category)
897 {
898  // insert new smartplaylistcategory
899 
900  MSqlQuery query(MSqlQuery::InitCon());
901  query.prepare("INSERT INTO music_smartplaylist_categories (name) "
902  "VALUES (:NAME);");
903  query.bindValue(":NAME", category);
904 
905  if (!query.exec())
906  {
907  MythDB::DBError("Inserting new smartplaylist category", query);
908  return;
909  }
910 
912  m_categorySelector->SetValue(category);
913 }
914 
915 void SmartPlaylistEditor::startDeleteCategory(const QString &category)
916 {
917  if (category.isEmpty())
918  return;
919 
920 //FIXME::
921 #if 0
922  if (!MythPopupBox::showOkCancelPopup(GetMythMainWindow(),
923  "Delete Category",
924  tr("Are you sure you want to delete this Category?")
925  + "\n\n\"" + category + "\"\n\n"
926  + tr("It will also delete any Smart Playlists belonging to this category."),
927  false))
928  return;
929 
931 #endif
933  m_titleEdit->Reset();
934 }
935 
936 void SmartPlaylistEditor::renameCategory(const QString &category)
937 {
938  if (m_categorySelector->GetValue() == category)
939  return;
940 
941  // change the category
942  MSqlQuery query(MSqlQuery::InitCon());
943  query.prepare("UPDATE music_smartplaylist_categories SET name = :NEW_CATEGORY "
944  "WHERE name = :OLD_CATEGORY;");
945  query.bindValue(":OLD_CATEGORY", m_categorySelector->GetValue());
946  query.bindValue(":NEW_CATEGORY", category);
947 
948  if (!query.exec())
949  MythDB::DBError("Rename smartplaylist", query);
950 
951  if (!m_newPlaylist)
953 
955  m_categorySelector->SetValue(category);
956 }
957 
958 QString SmartPlaylistEditor::getSQL(const QString& fields)
959 {
960  QString sql;
961  QString whereClause;
962  QString orderByClause;
963  QString limitClause;
964  sql = "SELECT " + fields + " FROM music_songs "
965  "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
966  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
967  "LEFT JOIN music_artists AS music_comp_artists ON music_albums.artist_id=music_comp_artists.artist_id "
968  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
969 
970  whereClause = getWhereClause();
971  orderByClause = getOrderByClause();
972  if (m_limitSpin->GetIntValue() > 0)
973  limitClause = " LIMIT " + m_limitSpin->GetValue();
974 
975  sql = sql + whereClause + orderByClause + limitClause;
976 
977  return sql;
978 }
979 
981 {
983 }
984 
986 {
987  if (m_criteriaRows.empty())
988  return {};
989 
990  bool bFirst = true;
991  QString sql = "WHERE ";
992 
993  for (const auto & row : std::as_const(m_criteriaRows))
994  {
995  QString criteria = row->getSQL();
996  if (criteria.isEmpty())
997  continue;
998 
999  if (bFirst)
1000  {
1001  sql += criteria;
1002  bFirst = false;
1003  }
1004  else
1005  {
1006  if (m_matchSelector->GetValue() == tr("Any"))
1007  sql += " OR " + criteria;
1008  else
1009  sql += " AND " + criteria;
1010  }
1011  }
1012 
1013  return sql;
1014 }
1015 
1017 {
1018  QString sql = getSQL("song_id, music_artists.artist_name, album_name, "
1019  "name, genre, music_songs.year, track");
1020 
1022 
1023  auto *resultViewer = new SmartPLResultViewer(mainStack);
1024 
1025  if (!resultViewer->Create())
1026  {
1027  delete resultViewer;
1028  return;
1029  }
1030 
1031  resultViewer->setSQL(sql);
1032 
1033  mainStack->AddScreen(resultViewer);
1034 }
1035 
1037 {
1038  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1039 
1040  auto *orderByDialog = new SmartPLOrderByDialog(popupStack);
1041 
1042  if (!orderByDialog->Create())
1043  {
1044  delete orderByDialog;
1045  return;
1046  }
1047 
1048  orderByDialog->setFieldList(m_orderBySelector->GetValue());
1049 
1050  connect(orderByDialog, qOverload<QString>(&SmartPLOrderByDialog::orderByChanged),
1052 
1053  popupStack->AddScreen(orderByDialog);
1054 }
1055 
1056 void SmartPlaylistEditor::orderByChanged(const QString& orderBy)
1057 {
1058  if (m_orderBySelector->MoveToNamedPosition(orderBy))
1059  return;
1060 
1061  // not found so add it to the selector
1063  m_orderBySelector->SetValue(orderBy);
1064 }
1065 
1067 {
1069  MSqlQuery query(MSqlQuery::InitCon());
1070 
1071  if (query.exec("SELECT name FROM music_smartplaylist_categories ORDER BY name;"))
1072  {
1073  if (query.isActive() && query.size() > 0)
1074  {
1075  while (query.next())
1076  new MythUIButtonListItem(m_categorySelector, query.value(0).toString());
1077  }
1078  else
1079  {
1080  LOG(VB_GENERAL, LOG_ERR,
1081  "Could not find any smartplaylist categories");
1082  }
1083  }
1084  else
1085  {
1086  MythDB::DBError("Load smartplaylist categories", query);
1087  }
1088 }
1089 
1090 // static function to delete a smartplaylist and any associated smartplaylist items
1091 bool SmartPlaylistEditor::deleteSmartPlaylist(const QString &category, const QString& name)
1092 {
1093  // get categoryid
1094  int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
1095 
1096  MSqlQuery query(MSqlQuery::InitCon());
1097 
1098  // get playlist ID
1099  int ID = -1;
1100  query.prepare("SELECT smartplaylistid FROM music_smartplaylists WHERE name = :NAME "
1101  "AND categoryid = :CATEGORYID;");
1102  query.bindValue(":NAME", name);
1103  query.bindValue(":CATEGORYID", categoryid);
1104  if (query.exec())
1105  {
1106  if (query.isActive() && query.size() > 0)
1107  {
1108  query.first();
1109  ID = query.value(0).toInt();
1110  }
1111  else
1112  {
1113  // not always an error maybe we are trying to delete a playlist
1114  // that does not exist
1115  return true;
1116  }
1117  }
1118  else
1119  {
1120  MythDB::DBError("Delete smartplaylist", query);
1121  return false;
1122  }
1123 
1124  //delete smartplaylist items
1125  query.prepare("DELETE FROM music_smartplaylist_items WHERE smartplaylistid = :ID;");
1126  query.bindValue(":ID", ID);
1127  if (!query.exec())
1128  MythDB::DBError("Delete smartplaylist items", query);
1129 
1130  //delete smartplaylist
1131  query.prepare("DELETE FROM music_smartplaylists WHERE smartplaylistid = :ID;");
1132  query.bindValue(":ID", ID);
1133  if (!query.exec())
1134  MythDB::DBError("Delete smartplaylist", query);
1135 
1136  return true;
1137 }
1138 
1139 // static function to delete all smartplaylists belonging to the given category
1140 // will also delete any associated smartplaylist items
1141 bool SmartPlaylistEditor::deleteCategory(const QString& category)
1142 {
1143  int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
1144  MSqlQuery query(MSqlQuery::InitCon());
1145 
1146  //delete all smartplaylists with the selected category
1147  query.prepare("SELECT name FROM music_smartplaylists "
1148  "WHERE categoryid = :CATEGORYID;");
1149  query.bindValue(":CATEGORYID", categoryid);
1150  if (!query.exec())
1151  {
1152  MythDB::DBError("Delete SmartPlaylist Category", query);
1153  return false;
1154  }
1155 
1156  if (query.isActive() && query.size() > 0)
1157  {
1158  while (query.next())
1159  {
1160  SmartPlaylistEditor::deleteSmartPlaylist(category, query.value(0).toString());
1161  }
1162  }
1163 
1164  // delete the category
1165  query.prepare("DELETE FROM music_smartplaylist_categories WHERE categoryid = :ID;");
1166  query.bindValue(":ID", categoryid);
1167  if (!query.exec())
1168  MythDB::DBError("Delete smartplaylist category", query);
1169 
1170  return true;
1171 }
1172 
1173 // static function to lookup the categoryid given its name
1174 int SmartPlaylistEditor::lookupCategoryID(const QString& category)
1175 {
1176  int ID = -1;
1177  MSqlQuery query(MSqlQuery::InitCon());
1178  query.prepare("SELECT categoryid FROM music_smartplaylist_categories "
1179  "WHERE name = :CATEGORY;");
1180  query.bindValue(":CATEGORY", category);
1181 
1182  if (query.exec())
1183  {
1184  if (query.isActive() && query.size() > 0)
1185  {
1186  query.first();
1187  ID = query.value(0).toInt();
1188  }
1189  else
1190  {
1191  LOG(VB_GENERAL, LOG_ERR,
1192  QString("Failed to find smart playlist category: %1")
1193  .arg(category));
1194  ID = -1;
1195  }
1196  }
1197  else
1198  {
1199  MythDB::DBError("Getting category ID", query);
1200  ID = -1;
1201  }
1202 
1203  return ID;
1204 }
1205 
1206 void SmartPlaylistEditor::getCategoryAndName(QString &category, QString &name)
1207 {
1208  category = m_categorySelector->GetValue();
1209  name = m_titleEdit->GetText();
1210 }
1211 
1212 /*
1213 ---------------------------------------------------------------------
1214 */
1215 
1217 {
1218  if (!LoadWindowFromXML("music-ui.xml", "criteriaroweditor", this))
1219  return false;
1220 
1221  bool err = false;
1222 
1223  UIUtilE::Assign(this, m_fieldSelector, "fieldselector", &err);
1224  UIUtilE::Assign(this, m_operatorSelector, "operatorselector", &err);
1225  UIUtilE::Assign(this, m_value1Edit, "value1edit", &err);
1226  UIUtilE::Assign(this, m_value2Edit, "value2edit", &err);
1227  UIUtilE::Assign(this, m_value1Selector, "value1selector", &err);
1228  UIUtilE::Assign(this, m_value2Selector, "value2selector", &err);
1229  UIUtilE::Assign(this, m_value1Spinbox, "value1spinbox", &err);
1230  UIUtilE::Assign(this, m_value2Spinbox, "value2spinbox", &err);
1231  UIUtilE::Assign(this, m_value1Button, "value1button", &err);
1232  UIUtilE::Assign(this, m_value2Button, "value2button", &err);
1233  UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
1234  UIUtilE::Assign(this, m_saveButton, "savebutton", &err);
1235 
1236  if (err)
1237  {
1238  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'criteriaroweditor'");
1239  return false;
1240  }
1241 
1242  updateFields();
1243  updateOperators();
1244  updateValues();
1245 
1248 
1253 
1256 
1259 
1260  BuildFocusList();
1261 
1262  return true;
1263 }
1264 
1266 {
1267  for (const auto & field : SmartPLFields)
1268  new MythUIButtonListItem(m_fieldSelector, field.m_name);
1269 
1271 }
1272 
1274 {
1275  for (const auto & oper : SmartPLOperators)
1276  new MythUIButtonListItem(m_operatorSelector, oper.m_name);
1277 
1279 }
1280 
1282 {
1283  enableSaveButton();
1284 }
1285 
1287 {
1292 
1294  {
1295  // not found so add it to the selector
1298  }
1299 
1301  {
1302  // not found so add it to the selector
1305  }
1306 }
1307 
1309 {
1310  const SmartPLField *Field = lookupField(m_fieldSelector->GetValue());
1311  if (!Field)
1312  return;
1313 
1316 
1317  if (Field->m_type == ftNumeric)
1318  {
1321  }
1322  else if (Field->m_type == ftBoolean || Field->m_type == ftDate)
1323  {
1326  }
1327  else // ftString
1328  {
1331  }
1332 
1333  // NOLINTNEXTLINE(readability-misleading-indentation)
1334  emit criteriaChanged();
1335 
1336  Close();
1337 }
1338 
1340 {
1341  bool enabled = false;
1342 
1343  const SmartPLField *Field = lookupField(m_fieldSelector->GetValue());
1344 
1346 
1347  if (Field && Operator)
1348  {
1349  if (Field->m_type == ftNumeric || Field->m_type == ftBoolean)
1350  enabled = true;
1351  else if (Field->m_type == ftDate)
1352  {
1353  if ((Operator->m_noOfArguments == 0) ||
1354  (Operator->m_noOfArguments == 1 && !m_value1Selector->GetValue().isEmpty()) ||
1355  (Operator->m_noOfArguments == 2 && !m_value1Selector->GetValue().isEmpty()
1356  && !m_value2Selector->GetValue().isEmpty()))
1357  enabled = true;
1358  }
1359  else // ftString
1360  {
1361  if ((Operator->m_noOfArguments == 0) ||
1362  (Operator->m_noOfArguments == 1 && !m_value1Edit->GetText().isEmpty()) ||
1363  (Operator->m_noOfArguments == 2 && !m_value1Edit->GetText().isEmpty()
1364  && !m_value2Edit->GetText().isEmpty()))
1365  enabled = true;
1366  }
1367  }
1368 
1369  m_saveButton->SetEnabled(enabled);
1370 }
1371 
1373 {
1374  const SmartPLField *Field = lookupField(m_fieldSelector->GetValue());
1375  if (!Field)
1376  return;
1377 
1378  if (Field->m_type == ftBoolean)
1379  {
1380  // add yes / no items to combo
1387  }
1388  else if (Field->m_type == ftDate)
1389  {
1390  // add a couple of date values to the combo
1392  new MythUIButtonListItem(m_value1Selector, "$DATE");
1393  new MythUIButtonListItem(m_value1Selector, "$DATE - 30 days");
1394  new MythUIButtonListItem(m_value1Selector, "$DATE - 60 days");
1395 
1397  {
1398  // not found so add it to the selector
1401  }
1402 
1403 
1405  new MythUIButtonListItem(m_value2Selector, "$DATE");
1406  new MythUIButtonListItem(m_value2Selector, "$DATE - 30 days");
1407  new MythUIButtonListItem(m_value2Selector, "$DATE - 60 days");
1408 
1410  {
1411  // not found so add it to the selector
1414  }
1415  }
1416 
1417  // get list of operators valid for this field type
1418  getOperatorList(Field->m_type);
1419 
1420  enableSaveButton();
1421 }
1422 
1424 {
1425  const SmartPLField *Field = lookupField(m_fieldSelector->GetValue());
1426  if (!Field)
1427  return;
1428 
1430  if (!Operator)
1431  return;
1432 
1433  // hide all widgets
1434  m_value1Edit->Hide();
1435  m_value2Edit->Hide();
1436  m_value1Button->Hide();
1437  m_value2Button->Hide();
1440  m_value1Spinbox->Hide();
1441  m_value2Spinbox->Hide();
1442 
1443  // show spin edits
1444  if (Field->m_type == ftNumeric)
1445  {
1446  if (Operator->m_noOfArguments >= 1)
1447  {
1448  m_value1Spinbox->Show();
1449  int currentValue = m_value1Spinbox->GetIntValue();
1450  m_value1Spinbox->SetRange(Field->m_minValue, Field->m_maxValue, 1);
1451 
1452  if (currentValue < Field->m_minValue || currentValue > Field->m_maxValue)
1454  }
1455 
1456  if (Operator->m_noOfArguments == 2)
1457  {
1458  m_value2Spinbox->Show();
1459  int currentValue = m_value2Spinbox->GetIntValue();
1460  m_value2Spinbox->SetRange(Field->m_minValue, Field->m_maxValue, 1);
1461 
1462  if (currentValue < Field->m_minValue || currentValue > Field->m_maxValue)
1464  }
1465  }
1466  else if (Field->m_type == ftBoolean)
1467  {
1468  // only show value1combo
1470  }
1471  else if (Field->m_type == ftDate)
1472  {
1473  if (Operator->m_noOfArguments >= 1)
1474  {
1476  m_value1Button->Show();
1477  }
1478 
1479  if (Operator->m_noOfArguments == 2)
1480  {
1482  m_value2Button->Show();
1483  }
1484  }
1485  else // ftString
1486  {
1487  if (Operator->m_noOfArguments >= 1)
1488  {
1489  m_value1Edit->Show();
1490  m_value1Button->Show();
1491  }
1492 
1493  if (Operator->m_noOfArguments == 2)
1494  {
1495  m_value2Edit->Show();
1496  m_value2Button->Show();
1497  }
1498  }
1499 
1500  enableSaveButton();
1501 }
1502 
1504 {
1505  QString currentOperator = m_operatorSelector->GetValue();
1506 
1508 
1509  for (const auto & oper : SmartPLOperators)
1510  {
1511  // don't add operators that only work with string fields
1512  if (fieldType != ftString && oper.m_stringOnly)
1513  continue;
1514 
1515  // don't add operators that only work with boolean fields
1516  if (fieldType == ftBoolean && !oper.m_validForBoolean)
1517  continue;
1518 
1519  new MythUIButtonListItem(m_operatorSelector, oper.m_name);
1520  }
1521 
1522  // try to set the operatorCombo to the same operator or else the first item
1523  m_operatorSelector->SetValue(currentOperator);
1524 }
1525 
1527 {
1528  QString msg;
1529  QStringList searchList;
1531 
1532  if (m_fieldSelector->GetValue() == "Artist")
1533  {
1534  msg = tr("Select an Artist");
1535  searchList = MusicMetadata::fillFieldList("artist");
1536  }
1537  else if (m_fieldSelector->GetValue() == "Comp. Artist")
1538  {
1539  msg = tr("Select a Compilation Artist");
1540  searchList = MusicMetadata::fillFieldList("compilation_artist");
1541  }
1542  else if (m_fieldSelector->GetValue() == "Album")
1543  {
1544  msg = tr("Select an Album");
1545  searchList = MusicMetadata::fillFieldList("album");
1546  }
1547  else if (m_fieldSelector->GetValue() == "Genre")
1548  {
1549  msg = tr("Select a Genre");
1550  searchList = MusicMetadata::fillFieldList("genre");
1551  }
1552  else if (m_fieldSelector->GetValue() == "Title")
1553  {
1554  msg = tr("Select a Title");
1555  searchList = MusicMetadata::fillFieldList("title");
1556  }
1557  else if ((m_fieldSelector->GetValue() == "Last Play") ||
1558  (m_fieldSelector->GetValue() == "Date Imported"))
1559  {
1560  editDate();
1561  return;
1562  }
1563 
1564  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1565  auto *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, s);
1566 
1567  if (!searchDlg->Create())
1568  {
1569  delete searchDlg;
1570  return;
1571  }
1572 
1573  connect(searchDlg, &MythUISearchDialog::haveResult, this, &CriteriaRowEditor::setValue);
1574 
1575  popupStack->AddScreen(searchDlg);
1576 }
1577 
1578 void CriteriaRowEditor::setValue(const QString& value)
1579 {
1581  m_value1Edit->SetText(value);
1582  else
1583  m_value2Edit->SetText(value);
1584 }
1585 
1587 {
1588  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1589  auto *dateDlg = new SmartPLDateDialog(popupStack);
1591 
1592  if (!dateDlg->Create())
1593  {
1594  delete dateDlg;
1595  return;
1596  }
1597 
1598  dateDlg->setDate(date);
1599 
1601 
1602  popupStack->AddScreen(dateDlg);
1603 }
1604 
1605 void CriteriaRowEditor::setDate(const QString& date)
1606 {
1608  {
1610  return;
1611 
1612  // not found so add it to the selector
1614  m_value1Selector->SetValue(date);
1615  }
1616  else
1617  {
1619  return;
1620 
1621  // not found so add it to the selector
1623  m_value2Selector->SetValue(date);
1624  }
1625 }
1626 
1627 /*
1628 ---------------------------------------------------------------------
1629 */
1630 
1631 
1633 {
1634  if (!LoadWindowFromXML("music-ui.xml", "smartplresultviewer", this))
1635  return false;
1636 
1637  bool err = false;
1638 
1639  UIUtilE::Assign(this, m_trackList, "tracklist", &err);
1640  UIUtilW::Assign(this, m_positionText, "position", &err);
1641 
1642  if (err)
1643  {
1644  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'smartplresultviewer'");
1645  return false;
1646  }
1647 
1652 
1653  BuildFocusList();
1654 
1655  return true;
1656 }
1657 
1659 {
1660  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
1661  return true;
1662 
1663  QStringList actions;
1664  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
1665 
1666  for (int i = 0; i < actions.size() && !handled; i++)
1667  {
1668  const QString& action = actions[i];
1669  handled = true;
1670 
1671  if (action == "INFO")
1672  showTrackInfo();
1673  else
1674  handled = false;
1675  }
1676 
1677  if (!handled && MythScreenType::keyPressEvent(event))
1678  handled = true;
1679 
1680  return handled;
1681 }
1682 
1684 {
1685  if (!item)
1686  return;
1687 
1688  if (item->GetImageFilename().isEmpty())
1689  {
1690  auto *mdata = item->GetData().value<MusicMetadata *>();
1691  if (mdata)
1692  {
1693  QString artFile = mdata->getAlbumArtFile();
1694  if (artFile.isEmpty())
1695  item->SetImage("mm_nothumb.png");
1696  else
1697  item->SetImage(mdata->getAlbumArtFile());
1698  }
1699  else
1700  {
1701  item->SetImage("mm_nothumb.png");
1702  }
1703  }
1704 }
1705 
1707 {
1708  if (!item || !m_positionText)
1709  return;
1710 
1711  m_positionText->SetText(tr("%1 of %2").arg(m_trackList->IsEmpty() ? 0 : m_trackList->GetCurrentPos() + 1)
1712  .arg(m_trackList->GetCount()));
1713 }
1715 {
1717  if (!item)
1718  return;
1719 
1720  auto *mdata = item->GetData().value<MusicMetadata *>();
1721  if (!mdata)
1722  return;
1723 
1724  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1725 
1726  auto *dlg = new TrackInfoDialog(popupStack, mdata, "trackinfopopup");
1727 
1728  if (!dlg->Create())
1729  {
1730  delete dlg;
1731  return;
1732  }
1733 
1734  popupStack->AddScreen(dlg);
1735 }
1736 
1737 void SmartPLResultViewer::setSQL(const QString& sql)
1738 {
1739  m_trackList->Reset();;
1740 
1741  MSqlQuery query(MSqlQuery::InitCon());
1742 
1743  if (query.exec(sql))
1744  {
1745  while (query.next())
1746  {
1747  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(query.value(0).toInt());
1748  if (mdata)
1749  {
1750  InfoMap metadataMap;
1751  mdata->toMap(metadataMap);
1752 
1753  auto *item = new MythUIButtonListItem(m_trackList, "", QVariant::fromValue(mdata));
1754  item->SetTextFromMap(metadataMap);
1755  }
1756  }
1757  }
1758 
1760 }
1761 
1762 
1763 /*
1764 ---------------------------------------------------------------------
1765 */
1766 
1768 {
1769  if (!LoadWindowFromXML("music-ui.xml", "orderbydialog", this))
1770  return false;
1771 
1772  bool err = false;
1773 
1774  UIUtilE::Assign(this, m_fieldList, "fieldlist", &err);
1775  UIUtilE::Assign(this, m_orderSelector, "fieldselector", &err);
1776  UIUtilE::Assign(this, m_addButton, "addbutton", &err);
1777  UIUtilE::Assign(this, m_deleteButton, "deletebutton", &err);
1778  UIUtilE::Assign(this, m_moveUpButton, "moveupbutton", &err);
1779  UIUtilE::Assign(this, m_moveDownButton, "movedownbutton", &err);
1780  UIUtilE::Assign(this, m_ascendingButton, "ascendingbutton", &err);
1781  UIUtilE::Assign(this, m_descendingButton, "descendingbutton", &err);
1782  UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
1783  UIUtilE::Assign(this, m_okButton, "okbutton", &err);
1784 
1785  if (err)
1786  {
1787  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'orderbydialog'");
1788  return false;
1789  }
1790 
1799 
1801  this, qOverload<MythUIButtonListItem *>(&SmartPLOrderByDialog::orderByChanged));
1804 
1805  getOrderByFields();
1806 
1807  orderByChanged();
1808 
1809  BuildFocusList();
1810 
1811  return true;
1812 }
1813 
1815 {
1816  QString result;
1817  bool bFirst = true;
1818 
1819  for (int i = 0; i < m_fieldList->GetCount(); i++)
1820  {
1821  if (bFirst)
1822  {
1823  bFirst = false;
1824  result = m_fieldList->GetItemAt(i)->GetText();
1825  }
1826  else
1827  {
1828  result += ", " + m_fieldList->GetItemAt(i)->GetText();
1829  }
1830  }
1831 
1832  return result;
1833 }
1834 
1835 void SmartPLOrderByDialog::setFieldList(const QString &fieldList)
1836 {
1837  m_fieldList->Reset();
1838  QStringList list = fieldList.split(",");
1839 
1840  for (int x = 0; x < list.count(); x++)
1841  {
1842  auto *item = new MythUIButtonListItem(m_fieldList, list[x].trimmed());
1843  QString state = list[x].contains("(A)") ? "ascending" : "descending";
1844  item->DisplayState(state, "sortstate");
1845  }
1846 
1847  orderByChanged();
1848 }
1849 
1851 {
1852  if (!item)
1853  return;
1854 
1855  m_orderSelector->SetValue(item->GetText().left(item->GetText().length() - 4));
1856 }
1857 
1859 {
1860  if (!m_fieldList->GetItemCurrent())
1861  return;
1862 
1864  m_fieldList->GetItemCurrent()->DisplayState("ascending", "sortstate");
1865 
1866  orderByChanged();
1868 }
1869 
1871 {
1872  if (!m_fieldList->GetItemCurrent())
1873  return;
1874 
1876  m_fieldList->GetItemCurrent()->DisplayState("descending", "sortstate");
1877 
1878  orderByChanged();
1880 }
1881 
1883 {
1884  auto *item = new MythUIButtonListItem(m_fieldList, m_orderSelector->GetValue() + " (A)");
1885  item->DisplayState("ascending", "sortstate");
1886 
1887  orderByChanged();
1889 }
1890 
1892 {
1894  orderByChanged();
1895 
1896  if (!m_deleteButton->IsEnabled())
1898  else
1900 }
1901 
1903 {
1905 
1906  if (item)
1907  item->MoveUpDown(true);
1908 
1909  orderByChanged();
1910 
1911  if (!m_moveUpButton->IsEnabled())
1913  else
1915 }
1916 
1918 {
1920 
1921  if (item)
1922  item->MoveUpDown(false);
1923 
1924  orderByChanged();
1925 
1926  if (!m_moveDownButton->IsEnabled())
1928  else
1930 }
1931 
1933 {
1934  emit orderByChanged(getFieldList());
1935  Close();
1936 }
1937 
1939 {
1940  bool found = false;
1941  for (int i = 0 ; i < m_fieldList->GetCount() ; ++i)
1942  {
1943  if (m_fieldList->GetItemAt(i)->GetText().startsWith(m_orderSelector->GetValue()))
1944  {
1946  found = true;
1947  }
1948  }
1949 
1950  if (found)
1951  {
1952  m_addButton->SetEnabled(false);
1953  m_deleteButton->SetEnabled(true);
1956  m_ascendingButton->SetEnabled((m_fieldList->GetValue().right(3) == "(D)") );
1957  m_descendingButton->SetEnabled((m_fieldList->GetValue().right(3) == "(A)"));
1958  }
1959  else
1960  {
1961  m_addButton->SetEnabled(true);
1962  m_deleteButton->SetEnabled(false);
1963  m_moveUpButton->SetEnabled(false);
1964  m_moveDownButton->SetEnabled(false);
1965  m_ascendingButton->SetEnabled(false);
1967  }
1968 }
1969 
1971 {
1972  orderByChanged();
1973 }
1974 
1976 {
1978  for (const auto & field : SmartPLFields)
1979  new MythUIButtonListItem(m_orderSelector, field.m_name);
1980 }
1981 
1982 /*
1983 ---------------------------------------------------------------------
1984 */
1985 
1987 {
1988  if (!LoadWindowFromXML("music-ui.xml", "dateeditordialog", this))
1989  return false;
1990 
1991  bool err = false;
1992 
1993  UIUtilE::Assign(this, m_fixedRadio, "fixeddatecheck", &err);
1994  UIUtilE::Assign(this, m_daySpin, "dayspinbox", &err);
1995  UIUtilE::Assign(this, m_monthSpin, "monthspinbox", &err);
1996  UIUtilE::Assign(this, m_yearSpin, "yearspinbox", &err);
1997  UIUtilE::Assign(this, m_nowRadio, "nowcheck", &err);
1998  UIUtilE::Assign(this, m_addDaysSpin, "adddaysspinbox", &err);
1999  UIUtilE::Assign(this, m_statusText, "statustext", &err);
2000  UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
2001  UIUtilE::Assign(this, m_okButton, "okbutton", &err);
2002 
2003  if (err)
2004  {
2005  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'dateeditordialog'");
2006  return false;
2007  }
2008 
2009  m_daySpin->SetRange(1, 31, 1);
2010  m_monthSpin->SetRange(1, 12, 1);
2011  m_yearSpin->SetRange(1900, 2099, 1);
2012  m_addDaysSpin->SetRange(-9999, 9999, 1);
2013 
2014 
2025 
2028 
2029  valueChanged();
2030 
2031  BuildFocusList();
2032 
2033  return true;
2034 }
2035 
2037 {
2038  QString sResult;
2039 
2041  {
2042  QString day = m_daySpin->GetValue();
2043  if (m_daySpin->GetIntValue() < 10)
2044  day = "0" + day;
2045 
2046  QString month = m_monthSpin->GetValue();
2047  if (m_monthSpin->GetIntValue() < 10)
2048  month = "0" + month;
2049 
2050  sResult = m_yearSpin->GetValue() + "-" + month + "-" + day;
2051  }
2052  else
2053  {
2054  sResult = m_statusText->GetText();
2055  }
2056 
2057  return sResult;
2058 }
2059 
2060 void SmartPLDateDialog::setDate(QString date)
2061 {
2062  if (date.startsWith("$DATE"))
2063  {
2064  m_nowRadio->SetCheckState(true);
2065  m_fixedRadio->SetCheckState(false);
2066 
2067  if (date.length() > 9)
2068  {
2069  bool bNegative = false;
2070  if (date[6] == '-')
2071  bNegative = true;
2072 
2073  if (date.endsWith(" days"))
2074  date = date.left(date.length() - 5);
2075 
2076  int nDays = date.mid(8).toInt();
2077  if (bNegative)
2078  nDays = -nDays;
2079 
2080  m_addDaysSpin->SetValue(nDays);
2081  }
2082  else
2083  {
2084  m_addDaysSpin->SetValue(0);
2085  }
2086 
2087  nowCheckToggled(true);
2088  }
2089  else
2090  {
2091  int nYear = date.mid(0, 4).toInt();
2092  int nMonth = date.mid(5, 2).toInt();
2093  int nDay = date.mid(8, 2).toInt();
2094 
2095  m_daySpin->SetValue(nDay);
2096  m_monthSpin->SetValue(nMonth);
2097  m_yearSpin->SetValue(nYear);
2098 
2099  fixedCheckToggled(true);
2100  }
2101 }
2102 
2104 {
2105  if (m_updating)
2106  return;
2107 
2108  m_updating = true;
2109  m_daySpin->SetEnabled(on);
2110  m_monthSpin->SetEnabled(on);
2111  m_yearSpin->SetEnabled(on);
2112 
2113  m_nowRadio->SetCheckState(!on);
2114  m_addDaysSpin->SetEnabled(!on);
2115 
2116  valueChanged();
2117 
2118  m_updating = false;
2119 }
2120 
2122 {
2123  if (m_updating)
2124  return;
2125 
2126  m_updating = true;
2127 
2129  m_daySpin->SetEnabled(!on);
2130  m_monthSpin->SetEnabled(!on);
2131  m_yearSpin->SetEnabled(!on);
2132 
2134 
2135  valueChanged();
2136 
2137  m_updating = false;
2138 }
2139 
2141 {
2142  QString date = getDate();
2143 
2144  emit dateChanged(date);
2145 
2146  Close();
2147 }
2148 
2150 {
2151  bool bValidDate = true;
2152 
2154  {
2155  QString day = m_daySpin->GetValue();
2156  if (m_daySpin->GetIntValue() < 10)
2157  day = "0" + day;
2158 
2159  QString month = m_monthSpin->GetValue();
2160  if (m_monthSpin->GetIntValue() < 10)
2161  month = "0" + month;
2162 
2163  QString sDate = m_yearSpin->GetValue() + "-" + month + "-" + day;
2164  QDate date = QDate::fromString(sDate, Qt::ISODate);
2165  if (date.isValid())
2166  m_statusText->SetText(date.toString("dddd, d MMMM yyyy"));
2167  else
2168  {
2169  bValidDate = false;
2170  m_statusText->SetText(tr("Invalid Date"));
2171  }
2172  }
2173  else if (m_nowRadio->GetBooleanCheckState())
2174  {
2175  QString days;
2176  if (m_addDaysSpin->GetIntValue() > 0)
2177  days = QString("$DATE + %1 days").arg(m_addDaysSpin->GetIntValue());
2178  else if (m_addDaysSpin->GetIntValue() == 0)
2179  days = QString("$DATE");
2180  else
2181  days = QString("$DATE - %1 days").arg(
2182  m_addDaysSpin->GetValue().right(m_addDaysSpin->GetValue().length() - 1));
2183 
2185  }
2186 
2187  if (bValidDate)
2188  m_statusText->SetFontState("valid");
2189  else
2190  m_statusText->SetFontState("error");
2191 
2192  m_okButton->SetEnabled(bValidDate);
2193 }
2194 
SmartPLOrderByDialog::m_moveUpButton
MythUIButton * m_moveUpButton
Definition: smartplaylist.h:276
SmartPLResultViewer::m_positionText
MythUIText * m_positionText
Definition: smartplaylist.h:235
MythUITextEdit::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitextedit.cpp:53
MythUIButton::Clicked
void Clicked()
MythUIText::SetFontState
void SetFontState(const QString &state)
Definition: mythuitext.cpp:202
SmartPLResultViewer::setSQL
void setSQL(const QString &sql)
Definition: smartplaylist.cpp:1737
MythUIButtonList::GetItemAt
MythUIButtonListItem * GetItemAt(int pos) const
Definition: mythuibuttonlist.cpp:1700
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
SmartPLOrderByDialog::moveDownPressed
void moveDownPressed(void)
Definition: smartplaylist.cpp:1917
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
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:317
SmartPlaylistEditor::loadFromDatabase
void loadFromDatabase(const QString &category, const QString &name)
Definition: smartplaylist.cpp:817
CriteriaRowEditor::valueEditChanged
void valueEditChanged(void)
Definition: smartplaylist.cpp:1281
MythUISearchDialog
Provide a dialog to quickly find an entry in a list.
Definition: mythdialogbox.h:399
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
MSqlQuery::bindValueNoNull
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:902
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1614
formattedFieldValue
QString formattedFieldValue(const QVariant &value)
Definition: smartplaylist.cpp:104
SmartPlaylistEditor::lookupCategoryID
static int lookupCategoryID(const QString &category)
Definition: smartplaylist.cpp:1174
mythuitext.h
CriteriaRowEditor::m_value2Spinbox
MythUISpinBox * m_value2Spinbox
Definition: smartplaylist.h:201
SmartPlaylistEditor::deleteSmartPlaylist
static bool deleteSmartPlaylist(const QString &category, const QString &name)
Definition: smartplaylist.cpp:1091
SmartPLDateDialog::m_statusText
MythUIText * m_statusText
Definition: smartplaylist.h:320
CriteriaRowEditor::m_value1Edit
MythUITextEdit * m_value1Edit
Definition: smartplaylist.h:194
MythUISpinBox::GetValue
QString GetValue(void) const override
Definition: mythuispinbox.h:31
mythdb.h
getOrderBySQL
QString getOrderBySQL(const QString &orderByFields)
Definition: smartplaylist.cpp:240
SmartPLOrderByDialog
Definition: smartplaylist.h:239
SmartPLField::m_name
QString m_name
Definition: smartplaylist.cpp:34
MythUIButtonList::Find
bool Find(const QString &searchStr, bool startsWith=false)
Definition: mythuibuttonlist.cpp:3181
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3613
SmartPlaylistEditor::orderByChanged
void orderByChanged(const QString &orderBy)
Definition: smartplaylist.cpp:1056
SmartPlaylistEditor::renameCategory
void renameCategory(const QString &category)
Definition: smartplaylist.cpp:936
SmartPLResultViewer::showTrackInfo
void showTrackInfo(void)
Definition: smartplaylist.cpp:1714
SmartPlaylistEditor::m_showResultsButton
MythUIButton * m_showResultsButton
Definition: smartplaylist.h:149
SmartPLOperators
static const std::array< const SmartPLOperator, 11 > SmartPLOperators
Definition: smartplaylist.cpp:70
SmartPLCriteriaRow::m_field
QString m_field
Definition: smartplaylist.h:64
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:383
SmartPlaylistEditor::showCategoryMenu
void showCategoryMenu(void)
Definition: smartplaylist.cpp:640
MusicMetadata::fillFieldList
static QStringList fillFieldList(const QString &field)
Definition: musicmetadata.cpp:1235
SmartPLOperator::m_validForBoolean
bool m_validForBoolean
Definition: smartplaylist.cpp:66
lookupOperator
static const SmartPLOperator * lookupOperator(const QString &name)
Definition: smartplaylist.cpp:84
MythUIButtonList::RemoveItem
void RemoveItem(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1512
CriteriaRowEditor::updateValues
void updateValues(void)
Definition: smartplaylist.cpp:1286
CriteriaRowEditor::saveClicked
void saveClicked(void)
Definition: smartplaylist.cpp:1308
SmartPLOrderByDialog::m_addButton
MythUIButton * m_addButton
Definition: smartplaylist.h:274
lookupField
static const SmartPLField * lookupField(const QString &name)
Definition: smartplaylist.cpp:94
MythUISearchDialog::haveResult
void haveResult(QString)
SmartPLOrderByDialog::addPressed
void addPressed(void)
Definition: smartplaylist.cpp:1882
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
SmartPlaylistEditor::m_newPlaylist
bool m_newPlaylist
Definition: smartplaylist.h:132
CriteriaRowEditor::setDate
void setDate(const QString &date)
Definition: smartplaylist.cpp:1605
SmartPLOperator
Definition: smartplaylist.cpp:61
TrackInfoDialog
Definition: musiccommon.h:236
SmartPLDateDialog::valueChanged
void valueChanged(void)
Definition: smartplaylist.cpp:2149
SmartPLOrderByDialog::m_okButton
MythUIButton * m_okButton
Definition: smartplaylist.h:281
MythUICheckBox::GetBooleanCheckState
bool GetBooleanCheckState(void) const
Definition: mythuicheckbox.cpp:103
SmartPLCriteriaRow::m_value1
QString m_value1
Definition: smartplaylist.h:66
SmartPLResultViewer
Definition: smartplaylist.h:213
SmartPlaylistEditor::saveClicked
void saveClicked(void)
Definition: smartplaylist.cpp:726
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MythScreenStack
Definition: mythscreenstack.h:16
ftString
@ ftString
Definition: smartplaylist.h:24
SmartPlaylistEditor::getSmartPlaylistCategories
void getSmartPlaylistCategories(void)
Definition: smartplaylist.cpp:1066
SmartPlaylistEditor::m_categorySelector
MythUIButtonList * m_categorySelector
Definition: smartplaylist.h:138
SmartPLOrderByDialog::descendingPressed
void descendingPressed(void)
Definition: smartplaylist.cpp:1870
SmartPlaylistEditor::m_playlistIsValid
bool m_playlistIsValid
Definition: smartplaylist.h:133
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
SmartPlaylistEditor::customEvent
void customEvent(QEvent *event) override
Definition: smartplaylist.cpp:461
SmartPlaylistEditor::getCategoryAndName
void getCategoryAndName(QString &category, QString &name)
Definition: smartplaylist.cpp:1206
SmartPlaylistEditor::m_criteriaList
MythUIButtonList * m_criteriaList
Definition: smartplaylist.h:142
SmartPlaylistEditor::Create
bool Create(void) override
Definition: smartplaylist.cpp:369
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
SmartPLCriteriaRow::getSQL
QString getSQL(void) const
Definition: smartplaylist.cpp:292
SmartPLOrderByDialog::ascendingPressed
void ascendingPressed(void)
Definition: smartplaylist.cpp:1858
SmartPLFieldType
SmartPLFieldType
Definition: smartplaylist.h:22
MusicMetadata
Definition: musicmetadata.h:81
SmartPLDateDialog::m_addDaysSpin
MythUISpinBox * m_addDaysSpin
Definition: smartplaylist.h:318
SmartPLCriteriaRow::m_operator
QString m_operator
Definition: smartplaylist.h:65
SmartPLOrderByDialog::m_deleteButton
MythUIButton * m_deleteButton
Definition: smartplaylist.h:275
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:50
SmartPLOrderByDialog::moveUpPressed
void moveUpPressed(void)
Definition: smartplaylist.cpp:1902
ftNumeric
@ ftNumeric
Definition: smartplaylist.h:25
CriteriaRowEditor::m_value2Button
MythUIButton * m_value2Button
Definition: smartplaylist.h:204
SmartPLOrderByDialog::m_moveDownButton
MythUIButton * m_moveDownButton
Definition: smartplaylist.h:277
MythTextInputDialog::haveResult
void haveResult(QString)
SmartPLOrderByDialog::okPressed
void okPressed(void)
Definition: smartplaylist.cpp:1932
SmartPlaylistEditor::m_matchSelector
MythUIButtonList * m_matchSelector
Definition: smartplaylist.h:141
MythUISpinBox::SetRange
void SetRange(int low, int high, int step, uint pageMultiple=5)
Set the lower and upper bounds of the spinbox, the interval and page amount.
Definition: mythuispinbox.cpp:26
mythuibuttonlist.h
SmartPLField::m_defaultValue
int m_defaultValue
Definition: smartplaylist.cpp:39
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1679
SmartPlaylistEditor::startDeleteCategory
void startDeleteCategory(const QString &category)
Definition: smartplaylist.cpp:915
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
SmartPlaylistEditor::newSmartPlaylist
void newSmartPlaylist(const QString &category)
Definition: smartplaylist.cpp:796
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:110
MythUICheckBox::toggled
void toggled(bool)
getCriteriaSQL
QString getCriteriaSQL(const QString &fieldName, const QString &operatorName, QString value1, QString value2)
Definition: smartplaylist.cpp:149
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MythUIButtonListItem::SetText
void SetText(const QString &text, const QString &name="", const QString &state="")
Definition: mythuibuttonlist.cpp:3319
CriteriaRowEditor::Create
bool Create(void) override
Definition: smartplaylist.cpp:1216
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
SmartPLOrderByDialog::getOrderByFields
void getOrderByFields(void)
Definition: smartplaylist.cpp:1975
MythUISpinBox::SetValue
void SetValue(int val) override
Definition: mythuispinbox.h:26
MythUITextEdit::SetText
void SetText(const QString &text, bool moveCursor=true)
Definition: mythuitextedit.cpp:198
SmartPLField::m_maxValue
int m_maxValue
Definition: smartplaylist.cpp:38
MythUIButtonList::IsEmpty
bool IsEmpty() const
Definition: mythuibuttonlist.cpp:1695
SmartPLDateDialog::m_daySpin
MythUISpinBox * m_daySpin
Definition: smartplaylist.h:313
SmartPLCriteriaRow
Definition: smartplaylist.h:44
mythdate.h
SmartPlaylistEditor::orderByClicked
void orderByClicked(void)
Definition: smartplaylist.cpp:1036
SmartPLDateDialog::dateChanged
void dateChanged(QString date)
MythUIType::Show
void Show(void)
Definition: mythuitype.cpp:1144
SmartPlaylistEditor::deleteCriteria
void deleteCriteria(void)
Definition: smartplaylist.cpp:544
ftBoolean
@ ftBoolean
Definition: smartplaylist.h:27
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
CriteriaRowEditor::editDate
void editDate(void)
Definition: smartplaylist.cpp:1586
SmartPlaylistEditor::m_originalCategory
QString m_originalCategory
Definition: smartplaylist.h:134
SmartPlaylistEditor::m_matchesText
MythUIText * m_matchesText
Definition: smartplaylist.h:145
MythUIButtonList::GetCurrentPos
int GetCurrentPos() const
Definition: mythuibuttonlist.h:240
CriteriaRowEditor::fieldChanged
void fieldChanged(void)
Definition: smartplaylist.cpp:1372
CriteriaRowEditor
Definition: smartplaylist.h:152
MusicMetadata::toMap
void toMap(InfoMap &metadataMap, const QString &prefix="")
Definition: musicmetadata.cpp:1103
MythUIType::IsEnabled
bool IsEnabled(void) const
Definition: mythuitype.h:117
SmartPLOrderByDialog::getFieldList
QString getFieldList(void)
Definition: smartplaylist.cpp:1814
MSqlQuery::first
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:822
CriteriaRowEditor::updateFields
void updateFields(void)
Definition: smartplaylist.cpp:1265
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:115
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
menu
static MythThemedMenu * menu
Definition: mythtv-setup.cpp:58
SmartPLResultViewer::Create
bool Create(void) override
Definition: smartplaylist.cpp:1632
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
SmartPLOrderByDialog::m_orderSelector
MythUIButtonList * m_orderSelector
Definition: smartplaylist.h:273
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1277
MythUISpinBox::GetIntValue
int GetIntValue(void) const override
Definition: mythuispinbox.h:33
SmartPLOperator::m_name
QString m_name
Definition: smartplaylist.cpp:63
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
SmartPLField::m_sqlName
QString m_sqlName
Definition: smartplaylist.cpp:35
CriteriaRowEditor::enableSaveButton
void enableSaveButton(void)
Definition: smartplaylist.cpp:1339
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:203
SmartPLCriteriaRow::toString
QString toString(void) const
Definition: smartplaylist.cpp:331
SmartPlaylistEditor::getWhereClause
QString getWhereClause(void)
Definition: smartplaylist.cpp:985
SmartPLDateDialog::getDate
QString getDate(void)
Definition: smartplaylist.cpp:2036
CriteriaRowEditor::m_fieldSelector
MythUIButtonList * m_fieldSelector
Definition: smartplaylist.h:191
CriteriaRowEditor::m_operatorSelector
MythUIButtonList * m_operatorSelector
Definition: smartplaylist.h:192
SmartPLCriteriaRow::m_value2
QString m_value2
Definition: smartplaylist.h:67
SmartPlaylistEditor::newCategory
void newCategory(const QString &category)
Definition: smartplaylist.cpp:896
SmartPlaylistEditor::m_titleEdit
MythUITextEdit * m_titleEdit
Definition: smartplaylist.h:140
SmartPlaylistEditor::titleChanged
void titleChanged(void)
Definition: smartplaylist.cpp:692
SmartPlaylistEditor::getOrderByClause
QString getOrderByClause(void)
Definition: smartplaylist.cpp:980
ftDate
@ ftDate
Definition: smartplaylist.h:26
SmartPLResultViewer::m_trackList
MythUIButtonList * m_trackList
Definition: smartplaylist.h:234
SmartPlaylistEditor::criteriaChanged
void criteriaChanged()
Definition: smartplaylist.cpp:606
SmartPLDateDialog::fixedCheckToggled
void fixedCheckToggled(bool on)
Definition: smartplaylist.cpp:2103
SmartPLDateDialog::m_cancelButton
MythUIButton * m_cancelButton
Definition: smartplaylist.h:322
SmartPlaylistEditor::m_matchesCount
int m_matchesCount
Definition: smartplaylist.h:131
MythUIType::SetEnabled
void SetEnabled(bool enable)
Definition: mythuitype.cpp:1128
SmartPLFields
static const std::array< const SmartPLField, 13 > SmartPLFields
Definition: smartplaylist.cpp:43
SmartPlaylistEditor::addCriteria
void addCriteria(void)
Definition: smartplaylist.cpp:575
SmartPLOperator::m_noOfArguments
int m_noOfArguments
Definition: smartplaylist.cpp:64
SmartPLDateDialog::setDate
void setDate(QString date)
Definition: smartplaylist.cpp:2060
SmartPlaylistEditor::~SmartPlaylistEditor
~SmartPlaylistEditor(void) override
Definition: smartplaylist.cpp:357
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
SmartPLDateDialog::m_updating
bool m_updating
Definition: smartplaylist.h:310
SmartPlaylistEditor::showCriteriaMenu
void showCriteriaMenu(void)
Definition: smartplaylist.cpp:663
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1651
SmartPLField
Definition: smartplaylist.cpp:32
smartplaylist.h
SmartPLOrderByDialog::setFieldList
void setFieldList(const QString &fieldList)
Definition: smartplaylist.cpp:1835
SmartPLOrderByDialog::orderByChanged
void orderByChanged(void)
Definition: smartplaylist.cpp:1938
CriteriaRowEditor::m_saveButton
MythUIButton * m_saveButton
Definition: smartplaylist.h:209
MythUIButtonList::itemVisible
void itemVisible(MythUIButtonListItem *item)
SmartPlaylistEditor::m_orderByButton
MythUIButton * m_orderByButton
Definition: smartplaylist.h:144
SmartPlaylistEditor::editSmartPlaylist
void editSmartPlaylist(const QString &category, const QString &name)
Definition: smartplaylist.cpp:808
SmartPlaylistEditor::doDeleteCriteria
void doDeleteCriteria(bool doit)
Definition: smartplaylist.cpp:555
musicdata.h
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
SmartPlaylistEditor::m_limitSpin
MythUISpinBox * m_limitSpin
Definition: smartplaylist.h:146
MythUIType::Hide
void Hide(void)
Definition: mythuitype.cpp:1139
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
musiccommon.h
SmartPLOrderByDialog::m_cancelButton
MythUIButton * m_cancelButton
Definition: smartplaylist.h:280
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:21
SmartPLDateDialog::m_okButton
MythUIButton * m_okButton
Definition: smartplaylist.h:323
SmartPlaylistEditor::deleteCategory
static bool deleteCategory(const QString &category)
Definition: smartplaylist.cpp:1141
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3368
mythuispinbox.h
mythuihelper.h
SmartPLOrderByDialog::m_descendingButton
MythUIButton * m_descendingButton
Definition: smartplaylist.h:279
SmartPlaylistEditor::m_orderBySelector
MythUIButtonList * m_orderBySelector
Definition: smartplaylist.h:143
std::chrono::days
duration< CHRONO_TYPE, ratio< 86400 > > days
Definition: mythchrono.h:25
SmartPLResultViewer::trackSelected
void trackSelected(MythUIButtonListItem *item)
Definition: smartplaylist.cpp:1706
CriteriaRowEditor::m_value2Selector
MythUIButtonList * m_value2Selector
Definition: smartplaylist.h:198
SmartPLOrderByDialog::fieldListSelectionChanged
void fieldListSelectionChanged(MythUIButtonListItem *item)
Definition: smartplaylist.cpp:1850
SmartPlaylistEditor::getSQL
QString getSQL(const QString &fields)
Definition: smartplaylist.cpp:958
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:401
SmartPLField::m_type
SmartPLFieldType m_type
Definition: smartplaylist.cpp:36
SmartPlaylistEditor::m_tempCriteriaRow
SmartPLCriteriaRow * m_tempCriteriaRow
Definition: smartplaylist.h:129
CriteriaRowEditor::m_value1Button
MythUIButton * m_value1Button
Definition: smartplaylist.h:203
SmartPLOrderByDialog::m_fieldList
MythUIButtonList * m_fieldList
Definition: smartplaylist.h:272
getSQLFieldName
QString getSQLFieldName(const QString &fieldName)
Definition: smartplaylist.cpp:277
mythuitextedit.h
MythUICheckBox::SetCheckState
void SetCheckState(MythUIStateType::StateType state)
Definition: mythuicheckbox.cpp:66
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
SmartPLOrderByDialog::m_ascendingButton
MythUIButton * m_ascendingButton
Definition: smartplaylist.h:278
SmartPLCriteriaRow::saveToDatabase
bool saveToDatabase(int smartPlaylistID) const
Definition: smartplaylist.cpp:305
CriteriaRowEditor::valueButtonClicked
void valueButtonClicked(void)
Definition: smartplaylist.cpp:1526
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
CriteriaRowEditor::criteriaChanged
void criteriaChanged()
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
SmartPlaylistEditor::m_originalName
QString m_originalName
Definition: smartplaylist.h:135
CriteriaRowEditor::setValue
void setValue(const QString &value)
Definition: smartplaylist.cpp:1578
MythUIButtonList::GetValue
virtual QString GetValue() const
Definition: mythuibuttonlist.cpp:1633
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
SmartPlaylistEditor::showResultsClicked
void showResultsClicked(void)
Definition: smartplaylist.cpp:1016
mythcontext.h
SmartPlaylistEditor::m_categoryButton
MythUIButton * m_categoryButton
Definition: smartplaylist.h:139
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::MoveToNamedPosition
bool MoveToNamedPosition(const QString &position_name)
Definition: mythuibuttonlist.cpp:2318
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1581
CriteriaRowEditor::m_value1Spinbox
MythUISpinBox * m_value1Spinbox
Definition: smartplaylist.h:200
build_compdb.action
action
Definition: build_compdb.py:9
SmartPLDateDialog::m_yearSpin
MythUISpinBox * m_yearSpin
Definition: smartplaylist.h:315
CriteriaRowEditor::m_value2Edit
MythUITextEdit * m_value2Edit
Definition: smartplaylist.h:195
SmartPLDateDialog::m_nowRadio
MythUICheckBox * m_nowRadio
Definition: smartplaylist.h:317
mythuibutton.h
CriteriaRowEditor::updateOperators
void updateOperators(void)
Definition: smartplaylist.cpp:1273
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
SmartPLDateDialog::nowCheckToggled
void nowCheckToggled(bool on)
Definition: smartplaylist.cpp:2121
MythUITextEdit::valueChanged
void valueChanged()
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:56
SmartPlaylistEditor::m_saveButton
MythUIButton * m_saveButton
Definition: smartplaylist.h:148
SmartPLResultViewer::trackVisible
static void trackVisible(MythUIButtonListItem *item)
Definition: smartplaylist.cpp:1683
SmartPLField::m_minValue
int m_minValue
Definition: smartplaylist.cpp:37
MythThemedMenuState::Create
bool Create(void) override
Definition: myththemedmenu.cpp:34
MythUIButtonListItem::GetImageFilename
QString GetImageFilename(const QString &name="") const
Definition: mythuibuttonlist.cpp:3573
SmartPLDateDialog::okPressed
void okPressed(void)
Definition: smartplaylist.cpp:2140
CriteriaRowEditor::getOperatorList
void getOperatorList(SmartPLFieldType fieldType)
Definition: smartplaylist.cpp:1503
SmartPLDateDialog::Create
bool Create(void) override
Definition: smartplaylist.cpp:1986
SmartPlaylistEditor::smartPLChanged
void smartPLChanged(const QString &category, const QString &name)
MythTextInputDialog
Dialog prompting the user to enter a text string.
Definition: mythdialogbox.h:314
MythUIText::GetText
QString GetText(void) const
Definition: mythuitext.h:43
SmartPLResultViewer::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: smartplaylist.cpp:1658
mythuicheckbox.h
SmartPlaylistEditor::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: smartplaylist.cpp:424
MythUIButtonList::SetValue
virtual void SetValue(int value)
Definition: mythuibuttonlist.h:216
SmartPLDateDialog
Definition: smartplaylist.h:284
CriteriaRowEditor::m_cancelButton
MythUIButton * m_cancelButton
Definition: smartplaylist.h:208
evaluateDateValue
static QString evaluateDateValue(QString sDate)
Definition: smartplaylist.cpp:121
mythmainwindow.h
SmartPlaylistEditor::m_criteriaRows
QList< SmartPLCriteriaRow * > m_criteriaRows
Definition: smartplaylist.h:128
SmartPlaylistEditor::editCriteria
void editCriteria(void)
Definition: smartplaylist.cpp:511
CriteriaRowEditor::operatorChanged
void operatorChanged(void)
Definition: smartplaylist.cpp:1423
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
SmartPlaylistEditor::m_cancelButton
MythUIButton * m_cancelButton
Definition: smartplaylist.h:147
CriteriaRowEditor::m_criteriaRow
SmartPLCriteriaRow * m_criteriaRow
Definition: smartplaylist.h:186
MythUIButtonListItem::MoveUpDown
bool MoveUpDown(bool flag)
Definition: mythuibuttonlist.cpp:3720
SmartPlaylistEditor::updateMatches
void updateMatches(void)
Definition: smartplaylist.cpp:697
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:566
musicmetadata.h
SmartPLDateDialog::m_monthSpin
MythUISpinBox * m_monthSpin
Definition: smartplaylist.h:314
SmartPLOrderByDialog::deletePressed
void deletePressed(void)
Definition: smartplaylist.cpp:1891
mythscreentype.h
SmartPLOrderByDialog::Create
bool Create(void) override
Definition: smartplaylist.cpp:1767
SmartPLDateDialog::m_fixedRadio
MythUICheckBox * m_fixedRadio
Definition: smartplaylist.h:312
MSqlQuery::driver
const QSqlDriver * driver(void) const
Definition: mythdbcon.h:220
CriteriaRowEditor::m_value1Selector
MythUIButtonList * m_value1Selector
Definition: smartplaylist.h:197
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
SmartPLOperator::m_stringOnly
bool m_stringOnly
Definition: smartplaylist.cpp:65