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;
268 result +=
", " + Field->
m_sqlName + order;
311 query.
prepare(
"INSERT INTO music_smartplaylist_items (smartplaylistid, field, operator,"
313 "VALUES (:SMARTPLAYLISTID, :FIELD, :OPERATOR, :VALUE1, :VALUE2);");
314 query.
bindValue(
":SMARTPLAYLISTID", smartPlaylistID);
342 result +=
" " + tr(
"and") +
" " +
m_value2;
390 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'smartplaylisteditor'");
402 if (field.m_name ==
"")
430 for (
int i = 0; i < actions.size() && !handled; i++)
432 QString
action = actions[i];
462 if (dce->GetResult() < 0)
465 QString resultid = dce->GetId();
466 QString resulttext = dce->GetResultText();
467 if (resultid ==
"categorymenu")
469 if (resulttext == tr(
"New Category"))
472 QString label = tr(
"Enter Name Of New Category");
484 else if (resulttext == tr(
"Delete Category"))
486 else if (resulttext == tr(
"Rename Category"))
527 if (!editor->Create())
589 if (!editor->Create())
628 item->
SetText(row->toString());
636 QString label = tr(
"Category Actions");
648 menu->SetReturnEvent(
this,
"categorymenu");
650 menu->AddButton(tr(
"New Category"),
nullptr);
651 menu->AddButton(tr(
"Delete Category"),
nullptr);
652 menu->AddButton(tr(
"Rename Category"),
nullptr);
659 QString label = tr(
"Criteria Actions");
671 menu->SetReturnEvent(
this,
"criteriamenu");
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 ";
708 if (!query.
exec(sql))
710 else if (query.
next())
741 query.
prepare(
"INSERT INTO music_smartplaylists (name, categoryid, matchtype, orderby, limitto) "
742 "VALUES (:NAME, :CATEGORYID, :MATCHTYPE, :ORDERBY, :LIMIT);");
744 query.
bindValue(
":CATEGORYID", categoryid);
745 query.
bindValue(
":MATCHTYPE", matchType);
757 query.
prepare(
"SELECT smartplaylistid FROM music_smartplaylists "
758 "WHERE categoryid = :CATEGORYID AND name = :NAME;");
759 query.
bindValue(
":CATEGORYID", categoryid);
766 ID = query.
value(0).toInt();
770 LOG(VB_GENERAL, LOG_ERR,
771 QString(
"Failed to find ID for smartplaylist: %1").arg(name));
783 row->saveToDatabase(ID);
819 query.
prepare(
"SELECT smartplaylistid, name, categoryid, matchtype, orderby, limitto "
820 "FROM music_smartplaylists WHERE name = :NAME AND categoryid = :CATEGORYID;");
822 query.
bindValue(
":CATEGORYID", categoryid);
828 ID = query.
value(0).toInt();
831 if (query.
value(3).toString() ==
"All")
836 QString orderBy = query.
value(4).toString();
848 LOG(VB_GENERAL, LOG_ERR,
849 QString(
"Cannot find smartplaylist: %1").arg(name));
861 query.
prepare(
"SELECT field, operator, value1, value2 "
862 "FROM music_smartplaylist_items WHERE smartplaylistid = :ID "
863 "ORDER BY smartplaylistitemid;");
868 if (query.
size() > 0)
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();
885 LOG(VB_GENERAL, LOG_WARNING,
886 QString(
"Got no smartplaylistitems for ID: ").arg(ID));
895 query.
prepare(
"INSERT INTO music_smartplaylist_categories (name) "
911 if (category.isEmpty())
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."),
937 query.
prepare(
"UPDATE music_smartplaylist_categories SET name = :NEW_CATEGORY "
938 "WHERE name = :OLD_CATEGORY;");
940 query.
bindValue(
":NEW_CATEGORY", category);
956 QString orderByClause;
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 ";
969 sql = sql + whereClause + orderByClause + limitClause;
985 QString sql =
"WHERE ";
989 QString criteria = row->getSQL();
990 if (criteria.isEmpty())
1001 sql +=
" OR " + criteria;
1003 sql +=
" AND " + criteria;
1012 QString sql =
getSQL(
"song_id, music_artists.artist_name, album_name, "
1013 "name, genre, music_songs.year, track");
1019 if (!resultViewer->Create())
1021 delete resultViewer;
1025 resultViewer->setSQL(sql);
1036 if (!orderByDialog->Create())
1038 delete orderByDialog;
1065 if (query.
exec(
"SELECT name FROM music_smartplaylist_categories ORDER BY name;"))
1069 while (query.
next())
1074 LOG(VB_GENERAL, LOG_ERR,
1075 "Could not find any smartplaylist categories");
1094 query.
prepare(
"SELECT smartplaylistid FROM music_smartplaylists WHERE name = :NAME "
1095 "AND categoryid = :CATEGORYID;");
1097 query.
bindValue(
":CATEGORYID", categoryid);
1103 ID = query.
value(0).toInt();
1119 query.
prepare(
"DELETE FROM music_smartplaylist_items WHERE smartplaylistid = :ID;");
1125 query.
prepare(
"DELETE FROM music_smartplaylists WHERE smartplaylistid = :ID;");
1141 query.
prepare(
"SELECT name FROM music_smartplaylists "
1142 "WHERE categoryid = :CATEGORYID;");
1143 query.
bindValue(
":CATEGORYID", categoryid);
1152 while (query.
next())
1159 query.
prepare(
"DELETE FROM music_smartplaylist_categories WHERE categoryid = :ID;");
1172 query.
prepare(
"SELECT categoryid FROM music_smartplaylist_categories "
1173 "WHERE name = :CATEGORY;");
1181 ID = query.
value(0).toInt();
1185 LOG(VB_GENERAL, LOG_ERR,
1186 QString(
"Failed to find smart playlist category: %1")
1232 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'criteriaroweditor'");
1335 bool enabled =
false;
1341 if (Field && Operator)
1446 if (currentValue < Field->m_minValue || currentValue > Field->
m_maxValue)
1456 if (currentValue < Field->m_minValue || currentValue > Field->
m_maxValue)
1506 if (fieldType !=
ftString && oper.m_stringOnly)
1510 if (fieldType ==
ftBoolean && !oper.m_validForBoolean)
1523 QStringList searchList;
1528 msg = tr(
"Select an Artist");
1533 msg = tr(
"Select a Compilation Artist");
1538 msg = tr(
"Select an Album");
1543 msg = tr(
"Select a Genre");
1548 msg = tr(
"Select a Title");
1561 if (!searchDlg->Create())
1586 if (!dateDlg->Create())
1592 dateDlg->setDate(date);
1638 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'smartplresultviewer'");
1657 QStringList actions;
1660 for (
int i = 0; i < actions.size() && !handled; i++)
1662 QString
action = actions[i];
1688 if (artFile.isEmpty())
1691 item->
SetImage(mdata->getAlbumArtFile());
1735 if (query.
exec(sql))
1737 while (query.
next())
1743 mdata->
toMap(metadataMap);
1746 item->SetTextFromMap(metadataMap);
1779 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'orderbydialog'");
1828 QStringList list = fieldList.split(
",");
1830 for (
int x = 0; x < list.count(); x++)
1833 QString state = list[x].contains(
"(A)") ?
"ascending" :
"descending";
1834 item->DisplayState(state,
"sortstate");
1875 item->DisplayState(
"ascending",
"sortstate");
1995 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'dateeditordialog'");
2038 month =
"0" + month;
2050 if (date.startsWith(
"$DATE"))
2055 if (date.length() > 9)
2057 bool bNegative =
false;
2061 if (date.endsWith(
" days"))
2062 date = date.left(date.length() - 5);
2064 int nDays = date.mid(8).toInt();
2077 int nYear = date.mid(0, 4).toInt();
2078 int nMonth = date.mid(5, 2).toInt();
2079 int nDay = date.mid(8, 2).toInt();
2137 bool bValidDate =
true;
2147 month =
"0" + month;
2165 days = QString(
"$DATE");
2167 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.