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(
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.
duration< CHRONO_TYPE, ratio< 86400 > > days
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)