44 { .m_name=
"", .m_sqlName=
"" },
45 { .m_name=
"Artist", .m_sqlName=
"music_artists.artist_name" },
46 { .m_name=
"Album", .m_sqlName=
"music_albums.album_name" },
47 { .m_name=
"Title", .m_sqlName=
"music_songs.name" },
48 { .m_name=
"Genre", .m_sqlName=
"music_genres.genre" },
49 { .m_name=
"Year", .m_sqlName=
"music_songs.year",
51 .m_minValue=1900, .m_maxValue=2099, .m_defaultValue=2000 },
52 { .m_name=
"Track No.", .m_sqlName=
"music_songs.track",
54 { .m_name=
"Rating", .m_sqlName=
"music_songs.rating",
56 { .m_name=
"Play Count", .m_sqlName=
"music_songs.numplays",
58 { .m_name=
"Compilation", .m_sqlName=
"music_albums.compilation",
60 { .m_name=
"Comp. Artist", .m_sqlName=
"music_comp_artists.artist_name",
62 { .m_name=
"Last Play", .m_sqlName=
"FROM_DAYS(TO_DAYS(music_songs.lastplay))",
64 { .m_name=
"Date Imported", .m_sqlName=
"FROM_DAYS(TO_DAYS(music_songs.date_entered))",
78 { .m_name=
"is equal to", .m_validForBoolean=
true },
79 { .m_name=
"is not equal to", .m_validForBoolean=
true },
80 { .m_name=
"is greater than" },
81 { .m_name=
"is less than" },
82 { .m_name=
"starts with", .m_stringOnly=
true },
83 { .m_name=
"ends with", .m_stringOnly=
true },
84 { .m_name=
"contains", .m_stringOnly=
true },
85 { .m_name=
"does not contain", .m_stringOnly=
true },
86 { .m_name=
"is between", .m_noOfArguments=2 },
87 { .m_name=
"is set", .m_noOfArguments=0 },
88 { .m_name=
"is not set", .m_noOfArguments=0 },
95 if (oper.m_name == name)
105 if (field.m_name == name)
113#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
114 QSqlField field(
"", value.type());
116 QSqlField field(
"", value.metaType());
121 field.setValue(value);
124 QString result = QString::fromUtf8(query.
driver()->formatValue(field).toLatin1().data());
130 if (sDate.startsWith(
"$DATE"))
134 if (sDate.length() > 9)
136 bool bNegative =
false;
140 if (sDate.endsWith(
" days"))
141 sDate = sDate.left(sDate.length() - 5);
143 int nDays = sDate.mid(8).toInt();
147 date = date.addDays(nDays);
157 QString value1, QString value2)
161 if (fieldName.isEmpty())
182 value1 = (value1 ==
"Yes") ?
"1":
"0";
183 value2 = (value2 ==
"Yes") ?
"1":
"0";
191 if (Operator->
m_name ==
"is equal to")
195 else if (Operator->
m_name ==
"is not equal to")
199 else if (Operator->
m_name ==
"is greater than")
203 else if (Operator->
m_name ==
"is less than")
207 else if (Operator->
m_name ==
"starts with")
211 else if (Operator->
m_name ==
"ends with")
215 else if (Operator->
m_name ==
"contains")
219 else if (Operator->
m_name ==
"does not contain")
223 else if (Operator->
m_name ==
"is between")
228 else if (Operator->
m_name ==
"is set")
230 result = result +
" IS NOT NULL";
232 else if (Operator->
m_name ==
"is not set")
234 result = result +
" IS NULL";
239 LOG(VB_GENERAL, LOG_ERR,
240 QString(
"getCriteriaSQL(): invalid operator '%1'")
249 if (orderByFields.isEmpty())
252 QStringList list = orderByFields.split(
",");
258 for (
int x = 0; x < list.count(); x++)
260 fieldName = list[x].trimmed();
264 if (fieldName.right(3) ==
"(D)")
272 result =
" ORDER BY " + Field->
m_sqlName + order;
276 result +=
", " + Field->
m_sqlName + order;
320 query.
prepare(
"INSERT INTO music_smartplaylist_items (smartplaylistid, field, operator,"
322 "VALUES (:SMARTPLAYLISTID, :FIELD, :OPERATOR, :VALUE1, :VALUE2);");
323 query.
bindValue(
":SMARTPLAYLISTID", smartPlaylistID);
355 result +=
" " + tr(
"and") +
" " +
m_value2;
403 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'smartplaylisteditor'");
415 if (field.m_name ==
"")
443 for (
int i = 0; i < actions.size() && !handled; i++)
445 const QString&
action = actions[i];
477 if (dce->GetResult() < 0)
480 QString resultid = dce->GetId();
481 QString resulttext = dce->GetResultText();
482 if (resultid ==
"categorymenu")
484 if (resulttext == tr(
"New Category"))
487 QString label = tr(
"Enter Name Of New Category");
499 else if (resulttext == tr(
"Delete Category"))
503 else if (resulttext == tr(
"Rename Category"))
544 if (!editor->Create())
606 if (!editor->Create())
645 item->
SetText(row->toString());
653 QString label = tr(
"Category Actions");
665 menu->SetReturnEvent(
this,
"categorymenu");
667 menu->AddButton(tr(
"New Category"),
nullptr);
668 menu->AddButton(tr(
"Delete Category"),
nullptr);
669 menu->AddButton(tr(
"Rename Category"),
nullptr);
676 QString label = tr(
"Criteria Actions");
688 menu->SetReturnEvent(
this,
"criteriamenu");
713 "LEFT JOIN music_artists ON "
714 " music_songs.artist_id=music_artists.artist_id "
715 "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
716 "LEFT JOIN music_artists AS music_comp_artists ON "
717 " music_albums.artist_id=music_comp_artists.artist_id "
718 "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
725 if (!query.
exec(sql))
727 else if (query.
next())
758 query.
prepare(
"INSERT INTO music_smartplaylists (name, categoryid, matchtype, orderby, limitto) "
759 "VALUES (:NAME, :CATEGORYID, :MATCHTYPE, :ORDERBY, :LIMIT);");
761 query.
bindValue(
":CATEGORYID", categoryid);
762 query.
bindValue(
":MATCHTYPE", matchType);
774 query.
prepare(
"SELECT smartplaylistid FROM music_smartplaylists "
775 "WHERE categoryid = :CATEGORYID AND name = :NAME;");
776 query.
bindValue(
":CATEGORYID", categoryid);
783 ID = query.
value(0).toInt();
787 LOG(VB_GENERAL, LOG_ERR,
788 QString(
"Failed to find ID for smartplaylist: %1").arg(name));
800 row->saveToDatabase(ID);
836 query.
prepare(
"SELECT smartplaylistid, name, categoryid, matchtype, orderby, limitto "
837 "FROM music_smartplaylists WHERE name = :NAME AND categoryid = :CATEGORYID;");
839 query.
bindValue(
":CATEGORYID", categoryid);
845 ID = query.
value(0).toInt();
848 if (query.
value(3).toString() ==
"All")
853 QString orderBy = query.
value(4).toString();
865 LOG(VB_GENERAL, LOG_ERR,
866 QString(
"Cannot find smartplaylist: %1").arg(name));
878 query.
prepare(
"SELECT field, operator, value1, value2 "
879 "FROM music_smartplaylist_items WHERE smartplaylistid = :ID "
880 "ORDER BY smartplaylistitemid;");
885 if (query.
size() > 0)
889 QString Field = query.
value(0).toString();
890 QString Operator = query.
value(1).toString();
891 QString Value1 = query.
value(2).toString();
892 QString Value2 = query.
value(3).toString();
902 LOG(VB_GENERAL, LOG_WARNING,
903 QString(
"Got no smartplaylistitems for ID: ").arg(ID));
912 query.
prepare(
"INSERT INTO music_smartplaylist_categories (name) "
928 if (category.isEmpty())
935 tr(
"Are you sure you want to delete this Category?")
936 +
"\n\n\"" + category +
"\"\n\n"
937 + tr(
"It will also delete any Smart Playlists belonging to this category."),
954 query.
prepare(
"UPDATE music_smartplaylist_categories SET name = :NEW_CATEGORY "
955 "WHERE name = :OLD_CATEGORY;");
957 query.
bindValue(
":NEW_CATEGORY", category);
973 QString orderByClause;
975 sql =
"SELECT " + fields +
" FROM music_songs "
976 "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
977 "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
978 "LEFT JOIN music_artists AS music_comp_artists ON music_albums.artist_id=music_comp_artists.artist_id "
979 "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
986 sql = sql + whereClause + orderByClause + limitClause;
1002 QString sql =
"WHERE ";
1006 QString criteria = row->getSQL();
1007 if (criteria.isEmpty())
1018 sql +=
" OR " + criteria;
1020 sql +=
" AND " + criteria;
1029 QString sql =
getSQL(
"song_id, music_artists.artist_name, album_name, "
1030 "name, genre, music_songs.year, track");
1036 if (!resultViewer->Create())
1038 delete resultViewer;
1042 resultViewer->setSQL(sql);
1053 if (!orderByDialog->Create())
1055 delete orderByDialog;
1082 if (query.
exec(
"SELECT name FROM music_smartplaylist_categories ORDER BY name;"))
1086 while (query.
next())
1091 LOG(VB_GENERAL, LOG_ERR,
1092 "Could not find any smartplaylist categories");
1111 query.
prepare(
"SELECT smartplaylistid FROM music_smartplaylists WHERE name = :NAME "
1112 "AND categoryid = :CATEGORYID;");
1114 query.
bindValue(
":CATEGORYID", categoryid);
1120 ID = query.
value(0).toInt();
1136 query.
prepare(
"DELETE FROM music_smartplaylist_items WHERE smartplaylistid = :ID;");
1142 query.
prepare(
"DELETE FROM music_smartplaylists WHERE smartplaylistid = :ID;");
1158 query.
prepare(
"SELECT name FROM music_smartplaylists "
1159 "WHERE categoryid = :CATEGORYID;");
1160 query.
bindValue(
":CATEGORYID", categoryid);
1169 while (query.
next())
1176 query.
prepare(
"DELETE FROM music_smartplaylist_categories WHERE categoryid = :ID;");
1189 query.
prepare(
"SELECT categoryid FROM music_smartplaylist_categories "
1190 "WHERE name = :CATEGORY;");
1198 ID = query.
value(0).toInt();
1202 LOG(VB_GENERAL, LOG_ERR,
1203 QString(
"Failed to find smart playlist category: %1")
1249 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'criteriaroweditor'");
1352 bool enabled =
false;
1358 if (Field && Operator)
1465 if (currentValue < Field->m_minValue || currentValue > Field->
m_maxValue)
1475 if (currentValue < Field->m_minValue || currentValue > Field->
m_maxValue)
1525 if (fieldType !=
ftString && oper.m_stringOnly)
1529 if (fieldType ==
ftBoolean && !oper.m_validForBoolean)
1542 QStringList searchList;
1547 msg = tr(
"Select an Artist");
1552 msg = tr(
"Select a Compilation Artist");
1557 msg = tr(
"Select an Album");
1562 msg = tr(
"Select a Genre");
1567 msg = tr(
"Select a Title");
1580 if (!searchDlg->Create())
1605 if (!dateDlg->Create())
1611 dateDlg->setDate(date);
1657 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'smartplresultviewer'");
1676 QStringList actions;
1679 for (
int i = 0; i < actions.size() && !handled; i++)
1681 const QString&
action = actions[i];
1707 if (artFile.isEmpty())
1710 item->
SetImage(mdata->getAlbumArtFile());
1756 if (query.
exec(sql))
1758 while (query.
next())
1764 mdata->
toMap(metadataMap);
1767 item->SetTextFromMap(metadataMap);
1800 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'orderbydialog'");
1851 QStringList list = fieldList.split(
",");
1853 for (
int x = 0; x < list.count(); x++)
1856 QString state = list[x].contains(
"(A)") ?
"ascending" :
"descending";
1857 item->DisplayState(state,
"sortstate");
1898 item->DisplayState(
"ascending",
"sortstate");
2018 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'dateeditordialog'");
2061 month =
"0" + month;
2075 if (date.startsWith(
"$DATE"))
2080 if (date.length() > 9)
2082 bool bNegative =
false;
2086 if (date.endsWith(
" days"))
2087 date = date.left(date.length() - 5);
2089 int nDays = date.mid(8).toInt();
2104 int nYear = date.mid(0, 4).toInt();
2105 int nMonth = date.mid(5, 2).toInt();
2106 int nDay = date.mid(8, 2).toInt();
2164 bool bValidDate =
true;
2174 month =
"0" + month;
2194 days = QString(
"$DATE");
2196 days = QString(
"$DATE - %1 days").arg(
MusicMetadata * getMetadata(int an_id)
MythUIButton * m_cancelButton
MythUIButtonList * m_fieldSelector
void setDate(const QString &date)
MythUIButtonList * m_value1Selector
MythUIButton * m_value1Button
void valueEditChanged(void)
MythUITextEdit * m_value1Edit
MythUIButton * m_value2Button
void getOperatorList(SmartPLFieldType fieldType)
MythUISpinBox * m_value1Spinbox
MythUIButtonList * m_value2Selector
void enableSaveButton(void)
bool Create(void) override
void setValue(const QString &value)
void operatorChanged(void)
MythUIButton * m_saveButton
SmartPLCriteriaRow * m_criteriaRow
MythUISpinBox * m_value2Spinbox
MythUITextEdit * m_value2Edit
void updateOperators(void)
MythUIButtonList * m_operatorSelector
void valueButtonClicked(void)
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
QVariant value(int i) const
bool isActive(void) const
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
const QSqlDriver * driver(void) const
static void DBError(const QString &where, const MSqlQuery &query)
Basic menu dialog, message and a list of options.
MythScreenStack * GetMainStack()
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool SetFocusWidget(MythUIType *widget=nullptr)
Dialog prompting the user to enter a text string.
void SetCheckState(MythUIStateType::StateType state)
bool GetBooleanCheckState(void) const
Provide a dialog to quickly find an entry in a list.
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.
void SetValue(int val) override
QString GetValue(void) const override
int GetIntValue(void) const override
QString GetText(void) const
void SetText(const QString &text, bool moveCursor=true)
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
QString GetText(void) const
void SetFontState(const QString &state)
virtual void SetText(const QString &text)
bool IsEnabled(void) const
void SetEnabled(bool enable)
bool saveToDatabase(int smartPlaylistID) const
QString toString(void) const
QString getSQL(void) const
void setDate(QString date)
MythUICheckBox * m_fixedRadio
MythUICheckBox * m_nowRadio
MythUISpinBox * m_daySpin
MythUIText * m_statusText
MythUIButton * m_okButton
MythUISpinBox * m_monthSpin
MythUIButton * m_cancelButton
MythUISpinBox * m_yearSpin
MythUISpinBox * m_addDaysSpin
void fixedCheckToggled(bool on)
void nowCheckToggled(bool on)
bool Create(void) override
void dateChanged(QString date)
void getOrderByFields(void)
MythUIButtonList * m_orderSelector
QString getFieldList(void)
bool Create(void) override
MythUIButton * m_addButton
MythUIButtonList * m_fieldList
MythUIButton * m_descendingButton
void setFieldList(const QString &fieldList)
MythUIButton * m_moveUpButton
void descendingPressed(void)
void fieldListSelectionChanged(MythUIButtonListItem *item)
void orderByChanged(void)
void moveDownPressed(void)
void ascendingPressed(void)
MythUIButton * m_cancelButton
MythUIButton * m_ascendingButton
MythUIButton * m_okButton
MythUIButton * m_moveDownButton
MythUIButton * m_deleteButton
void setSQL(const QString &sql)
MythUIText * m_positionText
MythUIButtonList * m_trackList
void trackSelected(MythUIButtonListItem *item)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
static void trackVisible(MythUIButtonListItem *item)
bool Create(void) override
void startDeleteCategory(const QString &category)
void renameCategory(const QString &category)
MythUIButton * m_orderByButton
void editSmartPlaylist(const QString &category, const QString &name)
MythUIButton * m_cancelButton
QString getWhereClause(void)
void customEvent(QEvent *event) override
MythUIButton * m_saveButton
void loadFromDatabase(const QString &category, const QString &name)
void showCategoryMenu(void)
void doDeleteCriteria(bool doit)
void showResultsClicked(void)
void smartPLChanged(const QString &category, const QString &name)
QString getOrderByClause(void)
MythUIButton * m_showResultsButton
MythUIButtonList * m_categorySelector
void showCriteriaMenu(void)
void deleteCriteria(void)
QString getSQL(const QString &fields)
void newCategory(const QString &category)
static bool deleteCategory(const QString &category)
MythUIButtonList * m_matchSelector
void orderByClicked(void)
MythUIButtonList * m_orderBySelector
void getSmartPlaylistCategories(void)
MythUIText * m_matchesText
bool Create(void) override
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
void orderByChanged(const QString &orderBy)
void getCategoryAndName(QString &category, QString &name)
QList< SmartPLCriteriaRow * > m_criteriaRows
static int lookupCategoryID(const QString &category)
MythUITextEdit * m_titleEdit
MythUIButton * m_categoryButton
MythUIButtonList * m_criteriaList
~SmartPlaylistEditor(void) override
MythUISpinBox * m_limitSpin
QString m_originalCategory
void newSmartPlaylist(const QString &category)
static bool deleteSmartPlaylist(const QString &category, const QString &name)
SmartPLCriteriaRow * m_tempCriteriaRow
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MythMainWindow * GetMythMainWindow(void)
static MythThemedMenu * menu
QHash< QString, QString > InfoMap
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
static const SmartPLOperator * lookupOperator(const QString &name)
QString getOrderBySQL(const QString &orderByFields)
static const std::array< const SmartPLOperator, 11 > SmartPLOperators
QString getSQLFieldName(const QString &fieldName)
QString getCriteriaSQL(const QString &fieldName, const QString &operatorName, QString value1, QString value2)
static const std::array< const SmartPLField, 13 > SmartPLFields
QString formattedFieldValue(const QVariant &value)
static QString evaluateDateValue(QString sDate)
static const SmartPLField * lookupField(const QString &name)
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)