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