Go to the documentation of this file.
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))",
57 {
"Date Imported",
"FROM_DAYS(TO_DAYS(music_songs.date_entered))",
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 },
88 if (oper.m_name == name)
98 if (field.m_name == name)
106 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
107 QSqlField field(
"", value.type());
109 QSqlField field(
"", value.metaType());
114 field.setValue(value);
117 QString result = QString::fromUtf8(query.
driver()->formatValue(field).toLatin1().data());
123 if (sDate.startsWith(
"$DATE"))
127 if (sDate.length() > 9)
129 bool bNegative =
false;
133 if (sDate.endsWith(
" days"))
134 sDate = sDate.left(sDate.length() - 5);
136 int nDays = sDate.mid(8).toInt();
140 date = date.addDays(nDays);
150 QString value1, QString value2)
154 if (fieldName.isEmpty())
175 value1 = (value1 ==
"Yes") ?
"1":
"0";
176 value2 = (value2 ==
"Yes") ?
"1":
"0";
184 if (Operator->
m_name ==
"is equal to")
188 else if (Operator->
m_name ==
"is not equal to")
192 else if (Operator->
m_name ==
"is greater than")
196 else if (Operator->
m_name ==
"is less than")
200 else if (Operator->
m_name ==
"starts with")
204 else if (Operator->
m_name ==
"ends with")
208 else if (Operator->
m_name ==
"contains")
212 else if (Operator->
m_name ==
"does not contain")
216 else if (Operator->
m_name ==
"is between")
221 else if (Operator->
m_name ==
"is set")
223 result = result +
" IS NOT NULL";
225 else if (Operator->
m_name ==
"is not set")
227 result = result +
" IS NULL";
232 LOG(VB_GENERAL, LOG_ERR,
233 QString(
"getCriteriaSQL(): invalid operator '%1'")
242 if (orderByFields.isEmpty())
245 QStringList list = orderByFields.split(
",");
251 for (
int x = 0; x < list.count(); x++)
253 fieldName = list[x].trimmed();
257 if (fieldName.right(3) ==
"(D)")
265 result =
" ORDER BY " + Field->
m_sqlName + order;
269 result +=
", " + Field->
m_sqlName + order;
313 query.
prepare(
"INSERT INTO music_smartplaylist_items (smartplaylistid, field, operator,"
315 "VALUES (:SMARTPLAYLISTID, :FIELD, :OPERATOR, :VALUE1, :VALUE2);");
316 query.
bindValue(
":SMARTPLAYLISTID", smartPlaylistID);
344 result +=
" " + tr(
"and") +
" " +
m_value2;
392 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'smartplaylisteditor'");
404 if (field.m_name ==
"")
432 for (
int i = 0; i < actions.size() && !handled; i++)
434 const QString&
action = actions[i];
466 if (dce->GetResult() < 0)
469 QString resultid = dce->GetId();
470 QString resulttext = dce->GetResultText();
471 if (resultid ==
"categorymenu")
473 if (resulttext == tr(
"New Category"))
476 QString label = tr(
"Enter Name Of New Category");
488 else if (resulttext == tr(
"Delete Category"))
492 else if (resulttext == tr(
"Rename Category"))
533 if (!editor->Create())
595 if (!editor->Create())
634 item->
SetText(row->toString());
642 QString label = tr(
"Category Actions");
654 menu->SetReturnEvent(
this,
"categorymenu");
656 menu->AddButton(tr(
"New Category"),
nullptr);
657 menu->AddButton(tr(
"Delete Category"),
nullptr);
658 menu->AddButton(tr(
"Rename Category"),
nullptr);
665 QString label = tr(
"Criteria Actions");
677 menu->SetReturnEvent(
this,
"criteriamenu");
702 "LEFT JOIN music_artists ON "
703 " music_songs.artist_id=music_artists.artist_id "
704 "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
705 "LEFT JOIN music_artists AS music_comp_artists ON "
706 " music_albums.artist_id=music_comp_artists.artist_id "
707 "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
714 if (!query.
exec(sql))
716 else if (query.
next())
747 query.
prepare(
"INSERT INTO music_smartplaylists (name, categoryid, matchtype, orderby, limitto) "
748 "VALUES (:NAME, :CATEGORYID, :MATCHTYPE, :ORDERBY, :LIMIT);");
750 query.
bindValue(
":CATEGORYID", categoryid);
751 query.
bindValue(
":MATCHTYPE", matchType);
763 query.
prepare(
"SELECT smartplaylistid FROM music_smartplaylists "
764 "WHERE categoryid = :CATEGORYID AND name = :NAME;");
765 query.
bindValue(
":CATEGORYID", categoryid);
772 ID = query.
value(0).toInt();
776 LOG(VB_GENERAL, LOG_ERR,
777 QString(
"Failed to find ID for smartplaylist: %1").arg(name));
789 row->saveToDatabase(ID);
825 query.
prepare(
"SELECT smartplaylistid, name, categoryid, matchtype, orderby, limitto "
826 "FROM music_smartplaylists WHERE name = :NAME AND categoryid = :CATEGORYID;");
828 query.
bindValue(
":CATEGORYID", categoryid);
834 ID = query.
value(0).toInt();
837 if (query.
value(3).toString() ==
"All")
842 QString orderBy = query.
value(4).toString();
854 LOG(VB_GENERAL, LOG_ERR,
855 QString(
"Cannot find smartplaylist: %1").arg(name));
867 query.
prepare(
"SELECT field, operator, value1, value2 "
868 "FROM music_smartplaylist_items WHERE smartplaylistid = :ID "
869 "ORDER BY smartplaylistitemid;");
874 if (query.
size() > 0)
878 QString Field = query.
value(0).toString();
879 QString Operator = query.
value(1).toString();
880 QString Value1 = query.
value(2).toString();
881 QString Value2 = query.
value(3).toString();
891 LOG(VB_GENERAL, LOG_WARNING,
892 QString(
"Got no smartplaylistitems for ID: ").arg(ID));
901 query.
prepare(
"INSERT INTO music_smartplaylist_categories (name) "
917 if (category.isEmpty())
924 tr(
"Are you sure you want to delete this Category?")
925 +
"\n\n\"" + category +
"\"\n\n"
926 + tr(
"It will also delete any Smart Playlists belonging to this category."),
943 query.
prepare(
"UPDATE music_smartplaylist_categories SET name = :NEW_CATEGORY "
944 "WHERE name = :OLD_CATEGORY;");
946 query.
bindValue(
":NEW_CATEGORY", category);
962 QString orderByClause;
964 sql =
"SELECT " + fields +
" FROM music_songs "
965 "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
966 "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
967 "LEFT JOIN music_artists AS music_comp_artists ON music_albums.artist_id=music_comp_artists.artist_id "
968 "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
975 sql = sql + whereClause + orderByClause + limitClause;
991 QString sql =
"WHERE ";
995 QString criteria = row->getSQL();
996 if (criteria.isEmpty())
1007 sql +=
" OR " + criteria;
1009 sql +=
" AND " + criteria;
1018 QString sql =
getSQL(
"song_id, music_artists.artist_name, album_name, "
1019 "name, genre, music_songs.year, track");
1025 if (!resultViewer->Create())
1027 delete resultViewer;
1031 resultViewer->setSQL(sql);
1042 if (!orderByDialog->Create())
1044 delete orderByDialog;
1071 if (query.
exec(
"SELECT name FROM music_smartplaylist_categories ORDER BY name;"))
1075 while (query.
next())
1080 LOG(VB_GENERAL, LOG_ERR,
1081 "Could not find any smartplaylist categories");
1100 query.
prepare(
"SELECT smartplaylistid FROM music_smartplaylists WHERE name = :NAME "
1101 "AND categoryid = :CATEGORYID;");
1103 query.
bindValue(
":CATEGORYID", categoryid);
1109 ID = query.
value(0).toInt();
1125 query.
prepare(
"DELETE FROM music_smartplaylist_items WHERE smartplaylistid = :ID;");
1131 query.
prepare(
"DELETE FROM music_smartplaylists WHERE smartplaylistid = :ID;");
1147 query.
prepare(
"SELECT name FROM music_smartplaylists "
1148 "WHERE categoryid = :CATEGORYID;");
1149 query.
bindValue(
":CATEGORYID", categoryid);
1158 while (query.
next())
1165 query.
prepare(
"DELETE FROM music_smartplaylist_categories WHERE categoryid = :ID;");
1178 query.
prepare(
"SELECT categoryid FROM music_smartplaylist_categories "
1179 "WHERE name = :CATEGORY;");
1187 ID = query.
value(0).toInt();
1191 LOG(VB_GENERAL, LOG_ERR,
1192 QString(
"Failed to find smart playlist category: %1")
1238 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'criteriaroweditor'");
1341 bool enabled =
false;
1347 if (Field && Operator)
1452 if (currentValue < Field->m_minValue || currentValue > Field->
m_maxValue)
1462 if (currentValue < Field->m_minValue || currentValue > Field->
m_maxValue)
1512 if (fieldType !=
ftString && oper.m_stringOnly)
1516 if (fieldType ==
ftBoolean && !oper.m_validForBoolean)
1529 QStringList searchList;
1534 msg = tr(
"Select an Artist");
1539 msg = tr(
"Select a Compilation Artist");
1544 msg = tr(
"Select an Album");
1549 msg = tr(
"Select a Genre");
1554 msg = tr(
"Select a Title");
1567 if (!searchDlg->Create())
1592 if (!dateDlg->Create())
1598 dateDlg->setDate(date);
1644 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'smartplresultviewer'");
1663 QStringList actions;
1666 for (
int i = 0; i < actions.size() && !handled; i++)
1668 const QString&
action = actions[i];
1694 if (artFile.isEmpty())
1697 item->
SetImage(mdata->getAlbumArtFile());
1743 if (query.
exec(sql))
1745 while (query.
next())
1751 mdata->
toMap(metadataMap);
1754 item->SetTextFromMap(metadataMap);
1787 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'orderbydialog'");
1838 QStringList list = fieldList.split(
",");
1840 for (
int x = 0; x < list.count(); x++)
1843 QString state = list[x].contains(
"(A)") ?
"ascending" :
"descending";
1844 item->DisplayState(state,
"sortstate");
1885 item->DisplayState(
"ascending",
"sortstate");
2005 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'dateeditordialog'");
2048 month =
"0" + month;
2062 if (date.startsWith(
"$DATE"))
2067 if (date.length() > 9)
2069 bool bNegative =
false;
2073 if (date.endsWith(
" days"))
2074 date = date.left(date.length() - 5);
2076 int nDays = date.mid(8).toInt();
2091 int nYear = date.mid(0, 4).toInt();
2092 int nMonth = date.mid(5, 2).toInt();
2093 int nDay = date.mid(8, 2).toInt();
2151 bool bValidDate =
true;
2161 month =
"0" + month;
2179 days = QString(
"$DATE");
2181 days = QString(
"$DATE - %1 days").arg(
MythUIButton * m_moveUpButton
MythUIText * m_positionText
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
void SetFontState(const QString &state)
void setSQL(const QString &sql)
bool isActive(void) const
void moveDownPressed(void)
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
MythScreenStack * GetMainStack()
void loadFromDatabase(const QString &category, const QString &name)
void valueEditChanged(void)
Provide a dialog to quickly find an entry in a list.
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
QString formattedFieldValue(const QVariant &value)
static int lookupCategoryID(const QString &category)
MythUISpinBox * m_value2Spinbox
static bool deleteSmartPlaylist(const QString &category, const QString &name)
MythUIText * m_statusText
MythUITextEdit * m_value1Edit
QString GetValue(void) const override
QString getOrderBySQL(const QString &orderByFields)
void orderByChanged(const QString &orderBy)
void renameCategory(const QString &category)
MythUIButton * m_showResultsButton
static const std::array< const SmartPLOperator, 11 > SmartPLOperators
void showCategoryMenu(void)
static const SmartPLOperator * lookupOperator(const QString &name)
MythUIButton * m_addButton
static const SmartPLField * lookupField(const QString &name)
void setDate(const QString &date)
MythUIButton * m_okButton
bool GetBooleanCheckState(void) const
QVariant value(int i) const
void getSmartPlaylistCategories(void)
MythUIButtonList * m_categorySelector
void descendingPressed(void)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void customEvent(QEvent *event) override
void getCategoryAndName(QString &category, QString &name)
MythUIButtonList * m_criteriaList
bool Create(void) override
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QString getSQL(void) const
void ascendingPressed(void)
MythUISpinBox * m_addDaysSpin
MythUIButton * m_deleteButton
QString GetText(void) const
MythUIButton * m_value2Button
MythUIButton * m_moveDownButton
MythUIButtonList * m_matchSelector
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 startDeleteCategory(const QString &category)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
void newSmartPlaylist(const QString &category)
MythUIType * GetFocusWidget(void) const
QString getCriteriaSQL(const QString &fieldName, const QString &operatorName, QString value1, QString value2)
QHash< QString, QString > InfoMap
bool Create(void) override
void getOrderByFields(void)
void SetValue(int val) override
void SetText(const QString &text, bool moveCursor=true)
MythUISpinBox * m_daySpin
void orderByClicked(void)
void dateChanged(QString date)
void deleteCriteria(void)
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
QString m_originalCategory
MythUIText * m_matchesText
bool IsEnabled(void) const
QString getFieldList(void)
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
bool SetFocusWidget(MythUIType *widget=nullptr)
Basic menu dialog, message and a list of options.
static MythThemedMenu * menu
bool Create(void) override
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
MythUIButtonList * m_orderSelector
int GetIntValue(void) const override
static void DBError(const QString &where, const MSqlQuery &query)
void enableSaveButton(void)
void BuildFocusList(void)
QString toString(void) const
QString getWhereClause(void)
MythUIButtonList * m_fieldSelector
MythUIButtonList * m_operatorSelector
void newCategory(const QString &category)
MythUITextEdit * m_titleEdit
QString getOrderByClause(void)
MythUIButtonList * m_trackList
void fixedCheckToggled(bool on)
MythUIButton * m_cancelButton
void SetEnabled(bool enable)
static const std::array< const SmartPLField, 13 > SmartPLFields
void setDate(QString date)
~SmartPlaylistEditor(void) override
void showCriteriaMenu(void)
MusicMetadata * getMetadata(int an_id)
void setFieldList(const QString &fieldList)
void orderByChanged(void)
MythUIButton * m_saveButton
MythUIButton * m_orderByButton
void editSmartPlaylist(const QString &category, const QString &name)
void doDeleteCriteria(bool doit)
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
MythUISpinBox * m_limitSpin
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
MythUIButton * m_cancelButton
MythUIButton * m_okButton
static bool deleteCategory(const QString &category)
MythUIButton * m_descendingButton
MythUIButtonList * m_orderBySelector
duration< CHRONO_TYPE, ratio< 86400 > > days
void trackSelected(MythUIButtonListItem *item)
MythUIButtonList * m_value2Selector
void fieldListSelectionChanged(MythUIButtonListItem *item)
QString getSQL(const QString &fields)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
SmartPLCriteriaRow * m_tempCriteriaRow
MythUIButton * m_value1Button
MythUIButtonList * m_fieldList
QString getSQLFieldName(const QString &fieldName)
void SetCheckState(MythUIStateType::StateType state)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
MythUIButton * m_ascendingButton
bool saveToDatabase(int smartPlaylistID) const
void valueButtonClicked(void)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
void setValue(const QString &value)
virtual void SetText(const QString &text)
void showResultsClicked(void)
MythUIButton * m_categoryButton
MythMainWindow * GetMythMainWindow(void)
MythUISpinBox * m_value1Spinbox
MythUISpinBox * m_yearSpin
MythUITextEdit * m_value2Edit
MythUICheckBox * m_nowRadio
void updateOperators(void)
MythScreenStack * GetStack(const QString &Stackname)
void nowCheckToggled(bool on)
MythUIButton * m_saveButton
static void trackVisible(MythUIButtonListItem *item)
void getOperatorList(SmartPLFieldType fieldType)
bool Create(void) override
void smartPLChanged(const QString &category, const QString &name)
Dialog prompting the user to enter a text string.
QString GetText(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIButton * m_cancelButton
static QString evaluateDateValue(QString sDate)
QList< SmartPLCriteriaRow * > m_criteriaRows
void operatorChanged(void)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
MythUIButton * m_cancelButton
SmartPLCriteriaRow * m_criteriaRow
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
MythUISpinBox * m_monthSpin
bool Create(void) override
MythUICheckBox * m_fixedRadio
const QSqlDriver * driver(void) const
MythUIButtonList * m_value1Selector
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.