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