MythTV  0.26-pre
smartplaylist.cpp
Go to the documentation of this file.
00001 // c/c++
00002 #include <unistd.h>
00003 #include <iostream>
00004 using namespace std;
00005 
00006 // qt
00007 #include <QSqlDriver>
00008 #include <QKeyEvent>
00009 #include <QSqlField>
00010 
00011 // mythtv
00012 #include <mythcontext.h>
00013 #include <mythmainwindow.h>
00014 #include <mythdb.h>
00015 #include <mythuihelper.h>
00016 #include <mythscreentype.h>
00017 #include <mythuitext.h>
00018 #include <mythuitextedit.h>
00019 #include <mythuibuttonlist.h>
00020 #include <mythuibutton.h>
00021 #include <mythuispinbox.h>
00022 #include <mythuicheckbox.h>
00023 #include <mythdialogbox.h>
00024 
00025 // mythmusic
00026 #include "smartplaylist.h"
00027 #include "metadata.h"
00028 #include "musiccommon.h"
00029 
00030 struct SmartPLField
00031 {
00032     QString name;
00033     QString sqlName;
00034     SmartPLFieldType type;
00035     int     minValue;
00036     int     maxValue;
00037     int     defaultValue;
00038 };
00039 
00040 static SmartPLField SmartPLFields[] =
00041 {
00042     { "",              "",                               ftString,   0,    0,    0 },
00043     { "Artist",        "music_artists.artist_name",      ftString,   0,    0,    0 },
00044     { "Album",         "music_albums.album_name",        ftString,   0,    0,    0 },
00045     { "Title",         "music_songs.name",               ftString,   0,    0,    0 },
00046     { "Genre",         "music_genres.genre",             ftString,   0,    0,    0 },
00047     { "Year",          "music_songs.year",               ftNumeric,  1900, 2099, 2000 },
00048     { "Track No.",     "music_songs.track",              ftNumeric,  0,    99,   0 },
00049     { "Rating",        "music_songs.rating",             ftNumeric,  0,    10,   0 },
00050     { "Play Count",    "music_songs.numplays",           ftNumeric,  0,    9999, 0 },
00051     { "Compilation",   "music_albums.compilation",       ftBoolean,  0,    0,    0 },
00052     { "Comp. Artist",  "music_comp_artists.artist_name", ftString,   0,    0,    0 },
00053     { "Last Play",     "FROM_DAYS(TO_DAYS(music_songs.lastplay))",
00054                                                          ftDate,     0,    0,    0 },
00055     { "Date Imported", "FROM_DAYS(TO_DAYS(music_songs.date_entered))",
00056                                                          ftDate,     0,    0,    0 },
00057 };
00058 
00059 struct SmartPLOperator
00060 {
00061     QString name;
00062     int     noOfArguments;
00063     bool    stringOnly;
00064     bool    validForBoolean;
00065 };
00066 
00067 static SmartPLOperator SmartPLOperators[] =
00068 {
00069     { "is equal to",      1,  false, true },
00070     { "is not equal to",  1,  false, true },
00071     { "is greater than",  1,  false, false },
00072     { "is less than",     1,  false, false },
00073     { "starts with",      1,  true,  false },
00074     { "ends with",        1,  true,  false },
00075     { "contains",         1,  true,  false },
00076     { "does not contain", 1,  true,  false },
00077     { "is between",       2,  false, false },
00078     { "is set",           0,  false, false },
00079     { "is not set",       0,  false, false },
00080 };
00081 
00082 static int SmartPLOperatorsCount = sizeof(SmartPLOperators) / sizeof(SmartPLOperators[0]);
00083 static int SmartPLFieldsCount = sizeof(SmartPLFields) / sizeof(SmartPLFields[0]);
00084 
00085 static SmartPLOperator *lookupOperator(QString name)
00086 {
00087     for (int x = 0; x < SmartPLOperatorsCount; x++)
00088     {
00089         if (SmartPLOperators[x].name == name)
00090             return &SmartPLOperators[x];
00091     }
00092     return NULL;
00093 }
00094 
00095 static SmartPLField *lookupField(QString name)
00096 {
00097     for (int x = 0; x < SmartPLFieldsCount; x++)
00098     {
00099         if (SmartPLFields[x].name == name)
00100             return &SmartPLFields[x];
00101     }
00102     return NULL;
00103 }
00104 
00105 QString formattedFieldValue(const QVariant &value)
00106 {
00107     QSqlField field("", value.type());
00108     if (value.isNull())
00109         field.clear();
00110     else
00111         field.setValue(value);
00112 
00113     MSqlQuery query(MSqlQuery::InitCon());
00114     QString result = QString::fromUtf8(query.driver()->formatValue(field).toAscii().data());
00115     return result;
00116 }
00117 
00118 static QString evaluateDateValue(QString sDate)
00119 {
00120     if (sDate.startsWith("$DATE"))
00121     {
00122         QDate date = QDate::currentDate();
00123 
00124         if (sDate.length() > 9)
00125         {
00126             bool bNegative = false;
00127             if (sDate[6] == '-')
00128                 bNegative = true;
00129 
00130             if (sDate.endsWith(" days"))
00131                 sDate = sDate.left(sDate.length() - 5);
00132 
00133             int nDays = sDate.mid(8).toInt();
00134             if (bNegative)
00135                 nDays = -nDays;
00136 
00137             date = date.addDays(nDays);
00138         }
00139 
00140         return date.toString(Qt::ISODate);
00141     }
00142 
00143     return sDate;
00144 }
00145 
00146 QString getCriteriaSQL(QString fieldName, QString operatorName,
00147                        QString value1, QString value2)
00148 {
00149     QString result;
00150 
00151     if (fieldName.isEmpty())
00152         return result;
00153 
00154     SmartPLField *Field;
00155     Field = lookupField(fieldName);
00156     if (!Field)
00157     {
00158         return "";
00159     }
00160 
00161     result = Field->sqlName;
00162 
00163     SmartPLOperator *Operator;
00164     Operator = lookupOperator(operatorName);
00165     if (!Operator)
00166     {
00167         return QString();
00168     }
00169 
00170     // convert boolean and date values
00171     if (Field->type == ftBoolean)
00172     {
00173         // compilation field uses 0 = false;  1 = true
00174         value1 = (value1 == "Yes") ? "1":"0";
00175         value2 = (value2 == "Yes") ? "1":"0";
00176     }
00177     else if (Field->type == ftDate)
00178     {
00179         value1 = evaluateDateValue(value1);
00180         value2 = evaluateDateValue(value2);
00181     }
00182 
00183     if (Operator->name == "is equal to")
00184     {
00185         result = result + " = " + formattedFieldValue(value1);
00186     }
00187     else if (Operator->name == "is not equal to")
00188     {
00189         result = result + " != " + formattedFieldValue(value1);
00190     }
00191     else if (Operator->name == "is greater than")
00192     {
00193         result = result + " > " + formattedFieldValue(value1);
00194     }
00195     else if (Operator->name == "is less than")
00196     {
00197         result = result + " < " + formattedFieldValue(value1);
00198     }
00199     else if (Operator->name == "starts with")
00200     {
00201         result = result + " LIKE " + formattedFieldValue(QString("%") + value1);
00202     }
00203     else if (Operator->name == "ends with")
00204     {
00205         result = result + " LIKE " + formattedFieldValue(value1 + "%");
00206     }
00207     else if (Operator->name == "contains")
00208     {
00209         result = result + " LIKE " + formattedFieldValue(QString("%") + value1 + "%");
00210     }
00211     else if (Operator->name == "does not contain")
00212     {
00213         result = result + " NOT LIKE " + formattedFieldValue(QString("%") + value1 + "%");
00214     }
00215     else if (Operator->name == "is between")
00216     {
00217         result = result + " BETWEEN " + formattedFieldValue(value1) +
00218                           " AND " + formattedFieldValue(value2);
00219     }
00220     else if (Operator->name == "is set")
00221     {
00222         result = result + " IS NOT NULL";
00223     }
00224     else if (Operator->name == "is not set")
00225     {
00226         result = result + " IS NULL";
00227     }
00228     else
00229     {
00230         result.clear();
00231         LOG(VB_GENERAL, LOG_ERR,
00232             QString("getCriteriaSQL(): invalid operator '%1'")
00233                 .arg(Operator->name));
00234     }
00235 
00236     return result;
00237 }
00238 
00239 QString getOrderBySQL(QString orderByFields)
00240 {
00241     if (orderByFields.isEmpty())
00242         return QString();
00243 
00244     QStringList list = orderByFields.split(",");
00245     QString fieldName, result, order;
00246     bool bFirst = true;
00247 
00248     for (int x = 0; x < list.count(); x++)
00249     {
00250         fieldName = list[x].trimmed();
00251         SmartPLField *Field;
00252         Field = lookupField(fieldName.left(fieldName.length() - 4));
00253         if (Field)
00254         {
00255             if (fieldName.right(3) == "(D)")
00256                 order = " DESC";
00257             else
00258                 order = " ASC";
00259 
00260            if (bFirst)
00261            {
00262                bFirst = false;
00263                result = " ORDER BY " + Field->sqlName + order;
00264            }
00265            else
00266                result += ", " + Field->sqlName + order;
00267         }
00268     }
00269 
00270     return result;
00271 }
00272 
00273 QString getSQLFieldName(QString fieldName)
00274 {
00275     SmartPLField *Field;
00276     Field = lookupField(fieldName);
00277     if (!Field)
00278     {
00279         return "";
00280     }
00281 
00282     return Field->sqlName;
00283 }
00284 
00285 /*
00287 */
00288 
00289 SmartPLCriteriaRow::SmartPLCriteriaRow(const QString &_Field, const QString &_Operator,
00290                                        const QString &_Value1, const QString &_Value2)
00291 {
00292     Field = _Field;
00293     Operator = _Operator;
00294     Value1 = _Value1;
00295     Value2 = _Value2;
00296 }
00297 
00298 SmartPLCriteriaRow::SmartPLCriteriaRow(void) :
00299     Field(""), Operator(""), Value1(""), Value2("")
00300 {
00301 }
00302 
00303 SmartPLCriteriaRow::~SmartPLCriteriaRow()
00304 {
00305 }
00306 
00307 QString SmartPLCriteriaRow::getSQL(void)
00308 {
00309     if (Field.isEmpty())
00310         return QString::null;
00311 
00312     QString result;
00313 
00314     result = getCriteriaSQL(Field, Operator, Value1, Value2);
00315 
00316     return result;
00317 }
00318 
00319 // return false on error
00320 bool SmartPLCriteriaRow::saveToDatabase(int smartPlaylistID)
00321 {
00322     // save playlistitem to database
00323 
00324     if (Field.isEmpty())
00325         return true;
00326 
00327     MSqlQuery query(MSqlQuery::InitCon());
00328     query.prepare("INSERT INTO music_smartplaylist_items (smartplaylistid, field, operator,"
00329                   " value1, value2)"
00330                   "VALUES (:SMARTPLAYLISTID, :FIELD, :OPERATOR, :VALUE1, :VALUE2);");
00331     query.bindValue(":SMARTPLAYLISTID", smartPlaylistID);
00332     query.bindValue(":FIELD", Field);
00333     query.bindValue(":OPERATOR", Operator);
00334     query.bindValue(":VALUE1", Value1);
00335     query.bindValue(":VALUE2", Value2);
00336 
00337     if (!query.exec())
00338     {
00339         MythDB::DBError("Inserting new smartplaylist item", query);
00340         return false;
00341     }
00342 
00343     return true;
00344 }
00345 
00346 QString SmartPLCriteriaRow::toString(void)
00347 {
00348     SmartPLOperator *PLOperator = lookupOperator(Operator);
00349     if (PLOperator)
00350     {
00351         QString result;
00352         if (PLOperator->noOfArguments == 0)
00353             result = Field + " " + Operator;
00354         else if (PLOperator->noOfArguments == 1)
00355             result = Field + " " + Operator + " " + Value1;
00356         else
00357         {
00358             result = Field + " " + Operator + " " + Value1;
00359             result += " " + QObject::tr("and") + " " + Value2;
00360         }
00361 
00362         return result;
00363     }
00364 
00365     return QString();
00366 }
00367 
00368 /*
00369 ---------------------------------------------------------------------
00370 */
00371 
00372 SmartPlaylistEditor::SmartPlaylistEditor(MythScreenStack *parent)
00373               : MythScreenType(parent, "smartplaylisteditor"),
00374                 m_tempCriteriaRow(NULL), m_matchesCount(0),
00375                 m_newPlaylist(false), m_playlistIsValid(false),
00376                 m_categorySelector(NULL), m_categoryButton(NULL),
00377                 m_titleEdit(NULL), m_matchSelector(NULL),
00378                 m_criteriaList(NULL), m_orderBySelector(NULL),
00379                 m_orderByButton(NULL), m_matchesText(NULL),
00380                 m_limitSpin(NULL), m_cancelButton(NULL),
00381                 m_saveButton(NULL), m_showResultsButton(NULL)
00382 {
00383 }
00384 
00385 SmartPlaylistEditor::~SmartPlaylistEditor(void)
00386 {
00387     while (!m_criteriaRows.empty())
00388     {
00389         delete m_criteriaRows.back();
00390         m_criteriaRows.pop_back();
00391     }
00392 
00393     if (m_tempCriteriaRow)
00394         delete m_tempCriteriaRow;
00395 }
00396 
00397 
00398 bool SmartPlaylistEditor::Create(void)
00399 {
00400     if (!LoadWindowFromXML("music-ui.xml", "smartplaylisteditor", this))
00401         return false;
00402 
00403     bool err = false;
00404 
00405     UIUtilE::Assign(this, m_categorySelector,  "categoryselector",  &err);
00406     UIUtilE::Assign(this, m_categoryButton,    "categorybutton",    &err);
00407     UIUtilE::Assign(this, m_titleEdit,         "titleedit",         &err);
00408     UIUtilE::Assign(this, m_matchSelector,     "matchselector",     &err);
00409     UIUtilE::Assign(this, m_criteriaList,      "criterialist",      &err);
00410     UIUtilE::Assign(this, m_orderBySelector,   "orderbyselector",   &err);
00411     UIUtilE::Assign(this, m_orderByButton,     "orderbybutton",     &err);
00412     UIUtilE::Assign(this, m_matchesText,       "matchestext",       &err);
00413     UIUtilE::Assign(this, m_limitSpin,         "limitspin",         &err);
00414 
00415     UIUtilE::Assign(this, m_cancelButton,      "cancelbutton",      &err);
00416     UIUtilE::Assign(this, m_saveButton,        "savebutton",        &err);
00417     UIUtilE::Assign(this, m_showResultsButton, "showresultsbutton", &err);
00418 
00419     if (err)
00420     {
00421         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'smartplaylisteditor'");
00422         return false;
00423     }
00424 
00425     getSmartPlaylistCategories();
00426 
00427     new MythUIButtonListItem(m_matchSelector, tr("All"));
00428     new MythUIButtonListItem(m_matchSelector, tr("Any"));
00429     connect(m_matchSelector, SIGNAL(itemSelected(MythUIButtonListItem*)), SLOT(updateMatches()));
00430 
00431     for (int x = 0; x < SmartPLFieldsCount; x++)
00432     {
00433         if (SmartPLFields[x].name == "")
00434             new MythUIButtonListItem(m_orderBySelector, SmartPLFields[x].name);
00435         else
00436             new MythUIButtonListItem(m_orderBySelector, SmartPLFields[x].name + " (A)");
00437     }
00438 
00439     m_limitSpin->SetRange(0, 9999, 10);
00440 
00441     connect(m_orderByButton, SIGNAL(Clicked()), SLOT(orderByClicked()));
00442     connect(m_saveButton, SIGNAL(Clicked()), SLOT(saveClicked()));
00443     connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close()));
00444     connect(m_categoryButton, SIGNAL(Clicked()), SLOT(showCategoryMenu()));
00445     connect(m_showResultsButton, SIGNAL(Clicked()), SLOT(showResultsClicked()));
00446     connect(m_criteriaList, SIGNAL(itemClicked(MythUIButtonListItem*)), SLOT(editCriteria()));
00447 
00448     BuildFocusList();
00449 
00450     return true;
00451 }
00452 
00453 bool SmartPlaylistEditor::keyPressEvent(QKeyEvent *event)
00454 {
00455     if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
00456         return true;
00457 
00458     bool handled = false;
00459     QStringList actions;
00460     handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
00461 
00462     for (int i = 0; i < actions.size() && !handled; i++)
00463     {
00464         QString action = actions[i];
00465         handled = true;
00466 
00467         if (action == "MENU")
00468         {
00469             showCriteriaMenu();
00470         }
00471         else if (action == "DELETE" && GetFocusWidget() == m_criteriaList)
00472         {
00473             deleteCriteria();
00474         }
00475         else if (action == "EDIT" && GetFocusWidget() == m_criteriaList)
00476         {
00477             editCriteria();
00478         }
00479         else
00480             handled = false;
00481     }
00482 
00483     if (!handled && MythScreenType::keyPressEvent(event))
00484         handled = true;
00485 
00486     return handled;
00487 }
00488 
00489 void SmartPlaylistEditor::customEvent(QEvent *event)
00490 {
00491     if (event->type() == DialogCompletionEvent::kEventType)
00492     {
00493         DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
00494 
00495         // make sure the user didn't ESCAPE out of the menu
00496         if (dce->GetResult() < 0)
00497             return;
00498 
00499         QString resultid   = dce->GetId();
00500         QString resulttext = dce->GetResultText();
00501         if (resultid == "categorymenu")
00502         {
00503             if (resulttext == tr("New Category"))
00504             {
00505                 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00506                 QString label = tr("Enter Name Of New Category");
00507 
00508                 MythTextInputDialog *input = new MythTextInputDialog(popupStack, label);
00509 
00510                 connect(input, SIGNAL(haveResult(QString)),
00511                         SLOT(newCategory(QString)));
00512 
00513                 if (input->Create())
00514                     popupStack->AddScreen(input);
00515                 else
00516                     delete input;
00517             }
00518             else if (resulttext == tr("Delete Category"))
00519                 startDeleteCategory(m_categorySelector->GetValue());
00520             else if (resulttext == tr("Rename Category"))
00521             {
00522                 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00523                 QString label = tr("Enter New Name For Category: %1").arg(m_categorySelector->GetValue());
00524 
00525                 MythTextInputDialog *input = new MythTextInputDialog(popupStack, label);
00526 
00527                 connect(input, SIGNAL(haveResult(QString)),
00528                         SLOT(renameCategory(QString)));
00529 
00530                 if (input->Create())
00531                     popupStack->AddScreen(input);
00532                 else
00533                     delete input;
00534             }
00535         }
00536     }
00537 }
00538 
00539 void SmartPlaylistEditor::editCriteria(void)
00540 {
00541     if (m_tempCriteriaRow)
00542     {
00543         delete m_tempCriteriaRow;
00544         m_tempCriteriaRow = NULL;
00545     }
00546 
00547     MythUIButtonListItem *item = m_criteriaList->GetItemCurrent();
00548 
00549     if (!item)
00550         return;
00551 
00552     SmartPLCriteriaRow *row = qVariantValue<SmartPLCriteriaRow*> (item->GetData());
00553 
00554     if (!row)
00555         return;
00556 
00557     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00558 
00559     CriteriaRowEditor *editor = new CriteriaRowEditor(popupStack, row);
00560 
00561     if (!editor->Create())
00562     {
00563         delete editor;
00564         return;
00565     }
00566 
00567     connect(editor, SIGNAL(criteriaChanged()), SLOT(criteriaChanged()));
00568 
00569     popupStack->AddScreen(editor);
00570 }
00571 
00572 void SmartPlaylistEditor::deleteCriteria(void)
00573 {
00574     // make sure we have something to delete
00575     MythUIButtonListItem *item = m_criteriaList->GetItemCurrent();
00576 
00577     if (!item)
00578         return;
00579 
00580     ShowOkPopup(tr("Delete Criteria?"), this, SLOT(doDeleteCriteria(bool)), true);
00581 }
00582 
00583 void SmartPlaylistEditor::doDeleteCriteria(bool doit)
00584 {
00585     if (doit)
00586     {
00587         MythUIButtonListItem *item = m_criteriaList->GetItemCurrent();
00588         if (!item)
00589             return;
00590 
00591         SmartPLCriteriaRow *row = qVariantValue<SmartPLCriteriaRow*> (item->GetData());
00592 
00593         if (!row)
00594             return;
00595 
00596         m_criteriaRows.removeAll(row);
00597         m_criteriaList->RemoveItem(item);
00598 
00599         criteriaChanged();
00600     }
00601 }
00602 
00603 void SmartPlaylistEditor::addCriteria(void)
00604 {
00605     /*
00606     SmartPLCriteriaRow *row = new SmartPLCriteriaRow();
00607     m_criteriaRows.append(row);
00608 
00609     MythUIButtonListItem *item = new MythUIButtonListItem(m_criteriaList, row->toString(), qVariantFromValue(row));
00610 
00611     m_criteriaList->SetItemCurrent(item);
00612 
00613     editCriteria();
00614     */
00615 
00616     if (m_tempCriteriaRow)
00617         delete m_tempCriteriaRow;
00618 
00619     m_tempCriteriaRow = new SmartPLCriteriaRow();
00620 
00621     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00622 
00623     CriteriaRowEditor *editor = new CriteriaRowEditor(popupStack, m_tempCriteriaRow);
00624 
00625     if (!editor->Create())
00626     {
00627         delete editor;
00628         return;
00629     }
00630 
00631     connect(editor, SIGNAL(criteriaChanged()), SLOT(criteriaChanged()));
00632 
00633     popupStack->AddScreen(editor);
00634 }
00635 
00636 void SmartPlaylistEditor::criteriaChanged()
00637 {
00638     MythUIButtonListItem *item = NULL;
00639 
00640     if (m_tempCriteriaRow)
00641     {
00642         // this is a new row so add it to the list
00643         m_criteriaRows.append(m_tempCriteriaRow);
00644 
00645         item = new MythUIButtonListItem(m_criteriaList, m_tempCriteriaRow->toString(),
00646                                         qVariantFromValue(m_tempCriteriaRow));
00647 
00648         m_criteriaList->SetItemCurrent(item);
00649 
00650         m_tempCriteriaRow = NULL;
00651     }
00652     else
00653     {
00654         // update the existing row
00655         item = m_criteriaList->GetItemCurrent();
00656         if (!item)
00657             return;
00658 
00659         SmartPLCriteriaRow *row = qVariantValue<SmartPLCriteriaRow*> (item->GetData());
00660 
00661         if (!row)
00662             return;
00663 
00664         item->SetText(row->toString());
00665     }
00666 
00667     updateMatches();
00668 }
00669 
00670 void SmartPlaylistEditor::showCategoryMenu(void)
00671 {
00672     QString label = tr("Category Actions");
00673 
00674     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00675 
00676     MythDialogBox *menu = new MythDialogBox(label, popupStack, "actionmenu");
00677 
00678     if (!menu->Create())
00679     {
00680         delete menu;
00681         return;
00682     }
00683 
00684     menu->SetReturnEvent(this, "categorymenu");
00685 
00686     menu->AddButton(tr("New Category"),    NULL);
00687     menu->AddButton(tr("Delete Category"), NULL);
00688     menu->AddButton(tr("Rename Category"), NULL);
00689 
00690     popupStack->AddScreen(menu);
00691 }
00692 
00693 void SmartPlaylistEditor::showCriteriaMenu(void)
00694 {
00695     QString label = tr("Criteria Actions");
00696 
00697     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00698 
00699     MythDialogBox *menu = new MythDialogBox(label, popupStack, "actionmenu");
00700 
00701     if (!menu->Create())
00702     {
00703         delete menu;
00704         return;
00705     }
00706 
00707     menu->SetReturnEvent(this, "criteriamenu");
00708 
00709     MythUIButtonListItem *item = m_criteriaList->GetItemCurrent();
00710 
00711     if (item)
00712         menu->AddButton(tr("Edit Criteria"), SLOT(editCriteria()));
00713 
00714     menu->AddButton(tr("Add Criteria"), SLOT(addCriteria()));
00715 
00716     if (item)
00717         menu->AddButton(tr("Delete Criteria"), SLOT(deleteCriteria()));
00718 
00719     popupStack->AddScreen(menu);
00720 }
00721 
00722 void SmartPlaylistEditor::titleChanged(void)
00723 {
00724     m_saveButton->SetEnabled((m_playlistIsValid && !m_titleEdit->GetText().isEmpty()));
00725 }
00726 
00727 void SmartPlaylistEditor::updateMatches(void)
00728 {
00729     QString sql =
00730         "SELECT count(*) "
00731         "FROM music_songs "
00732         "LEFT JOIN music_artists ON "
00733         "    music_songs.artist_id=music_artists.artist_id "
00734         "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
00735         "LEFT JOIN music_artists AS music_comp_artists ON "
00736         "    music_albums.artist_id=music_comp_artists.artist_id "
00737         "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
00738 
00739     sql += getWhereClause();
00740 
00741     m_matchesCount = 0;
00742 
00743     MSqlQuery query(MSqlQuery::InitCon());
00744     if (!query.exec(sql))
00745         MythDB::DBError("SmartPlaylistEditor::updateMatches", query);
00746     else if (query.next())
00747         m_matchesCount = query.value(0).toInt();
00748 
00749     m_matchesText->SetText(QString::number(m_matchesCount));
00750 
00751     m_playlistIsValid = (m_matchesCount > 0);
00752     m_showResultsButton->SetEnabled((m_matchesCount > 0));
00753     titleChanged();
00754 }
00755 
00756 void SmartPlaylistEditor::saveClicked(void)
00757 {
00758     // save smartplaylist to database
00759 
00760     QString name = m_titleEdit->GetText();
00761     QString category = m_categorySelector->GetValue();
00762     QString matchType = (m_matchSelector->GetValue() == tr("All") ? "All" : "Any");
00763     QString orderBy = m_orderBySelector->GetValue();
00764     QString limit = m_limitSpin->GetValue();
00765 
00766     // lookup categoryid
00767     int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
00768 
00769     // easier to delete any existing smartplaylist and recreate a new one
00770     if (!m_newPlaylist)
00771         SmartPlaylistEditor::deleteSmartPlaylist(m_originalCategory, m_originalName);
00772     else
00773         SmartPlaylistEditor::deleteSmartPlaylist(category, name);
00774 
00775     MSqlQuery query(MSqlQuery::InitCon());
00776     // insert new smartplaylist
00777     query.prepare("INSERT INTO music_smartplaylists (name, categoryid, matchtype, orderby, limitto) "
00778                 "VALUES (:NAME, :CATEGORYID, :MATCHTYPE, :ORDERBY, :LIMIT);");
00779     query.bindValue(":NAME", name);
00780     query.bindValue(":CATEGORYID", categoryid);
00781     query.bindValue(":MATCHTYPE", matchType);
00782     query.bindValue(":ORDERBY", orderBy);
00783     query.bindValue(":LIMIT", limit);
00784 
00785     if (!query.exec())
00786     {
00787         MythDB::DBError("Inserting new playlist", query);
00788         return;
00789     }
00790 
00791     // get smartplaylistid
00792     int ID;
00793     query.prepare("SELECT smartplaylistid FROM music_smartplaylists "
00794                   "WHERE categoryid = :CATEGORYID AND name = :NAME;");
00795     query.bindValue(":CATEGORYID", categoryid);
00796     query.bindValue(":NAME", name);
00797     if (query.exec())
00798     {
00799         if (query.isActive() && query.size() > 0)
00800         {
00801             query.first();
00802             ID = query.value(0).toInt();
00803         }
00804         else
00805         {
00806             LOG(VB_GENERAL, LOG_ERR,
00807                 QString("Failed to find ID for smartplaylist: %1").arg(name));
00808             return;
00809         }
00810     }
00811     else
00812     {
00813         MythDB::DBError("Getting smartplaylist ID", query);
00814         return;
00815     }
00816 
00817     // save smartplaylist items
00818     for (int x = 0; x < m_criteriaRows.size(); x++)
00819         m_criteriaRows[x]->saveToDatabase(ID);
00820 
00821     emit smartPLChanged(category, name);
00822 
00823     Close();
00824 }
00825 
00826 void SmartPlaylistEditor::newSmartPlaylist(QString category)
00827 {
00828     m_categorySelector->SetValue(category);
00829     m_titleEdit->Reset();
00830     m_originalCategory = category;
00831     m_originalName.clear();
00832 
00833     m_newPlaylist = true;
00834 
00835     updateMatches();
00836 }
00837 
00838 void SmartPlaylistEditor::editSmartPlaylist(QString category, QString name)
00839 {
00840     m_originalCategory = category;
00841     m_originalName = name;
00842     m_newPlaylist = false;
00843     loadFromDatabase(category, name);
00844     updateMatches();
00845 }
00846 
00847 void SmartPlaylistEditor::loadFromDatabase(QString category, QString name)
00848 {
00849     // load smartplaylist from database
00850     int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
00851 
00852     MSqlQuery query(MSqlQuery::InitCon());
00853     int ID;
00854 
00855     query.prepare("SELECT smartplaylistid, name, categoryid, matchtype, orderby, limitto "
00856                   "FROM music_smartplaylists WHERE name = :NAME AND categoryid = :CATEGORYID;");
00857     query.bindValue(":NAME", name);
00858     query.bindValue(":CATEGORYID", categoryid);
00859     if (query.exec())
00860     {
00861         if (query.isActive() && query.size() > 0)
00862         {
00863             query.first();
00864             ID = query.value(0).toInt();
00865             m_titleEdit->SetText(name);
00866             m_categorySelector->SetValue(category);
00867             if (query.value(3).toString() == "All")
00868                 m_matchSelector->SetValue(tr("All"));
00869             else
00870                 m_matchSelector->SetValue(tr("Any"));
00871 
00872             QString orderBy = query.value(4).toString();
00873             if (!m_orderBySelector->Find(orderBy))
00874             {
00875                 // not found so add it to the selector
00876                 new MythUIButtonListItem(m_orderBySelector, orderBy);
00877                 m_orderBySelector->SetValue(orderBy);
00878             }
00879 
00880             m_limitSpin->SetValue(query.value(5).toInt());
00881         }
00882         else
00883         {
00884             LOG(VB_GENERAL, LOG_ERR,
00885                 QString("Cannot find smartplaylist: %1").arg(name));
00886             return;
00887         }
00888     }
00889     else
00890     {
00891         MythDB::DBError("Load smartplaylist", query);
00892         return;
00893     }
00894 
00895     m_criteriaList->Reset();
00896 
00897     // load smartplaylist items
00898     SmartPLCriteriaRow *row;
00899 
00900     query.prepare("SELECT field, operator, value1, value2 "
00901                   "FROM music_smartplaylist_items WHERE smartplaylistid = :ID "
00902                   "ORDER BY smartplaylistitemid;");
00903     query.bindValue(":ID", ID);
00904     if (!query.exec())
00905         MythDB::DBError("Load smartplaylist items", query);
00906 
00907     if (query.size() > 0)
00908     {
00909         while (query.next())
00910         {
00911             QString Field = query.value(0).toString();
00912             QString Operator = query.value(1).toString();
00913             QString Value1 = query.value(2).toString();
00914             QString Value2 = query.value(3).toString();
00915             row = new SmartPLCriteriaRow(Field, Operator, Value1, Value2);
00916             m_criteriaRows.append(row);
00917 
00918             new MythUIButtonListItem(m_criteriaList, row->toString(), qVariantFromValue(row));
00919         }
00920     }
00921     else
00922     {
00923         LOG(VB_GENERAL, LOG_WARNING,
00924             QString("Got no smartplaylistitems for ID: ").arg(ID));
00925     }
00926 }
00927 
00928 void SmartPlaylistEditor::newCategory(const QString &category)
00929 {
00930     // insert new smartplaylistcategory
00931 
00932     MSqlQuery query(MSqlQuery::InitCon());
00933     query.prepare("INSERT INTO music_smartplaylist_categories (name) "
00934                 "VALUES (:NAME);");
00935     query.bindValue(":NAME", category);
00936 
00937     if (!query.exec())
00938     {
00939         MythDB::DBError("Inserting new smartplaylist category", query);
00940         return;
00941     }
00942 
00943     getSmartPlaylistCategories();
00944     m_categorySelector->SetValue(category);
00945 }
00946 
00947 void SmartPlaylistEditor::startDeleteCategory(const QString &category)
00948 {
00949     if (category.isEmpty())
00950         return;
00951 
00952 //FIXME::
00953 #if 0
00954     if (!MythPopupBox::showOkCancelPopup(GetMythMainWindow(),
00955             "Delete Category",
00956             tr("Are you sure you want to delete this Category?")
00957             + "\n\n\"" + category + "\"\n\n"
00958             + tr("It will also delete any Smart Playlists belonging to this category."),
00959              false))
00960         return;
00961 
00962     SmartPlaylistEditor::deleteCategory(category);
00963 #endif
00964     getSmartPlaylistCategories();
00965     m_titleEdit->Reset();
00966 }
00967 
00968 void SmartPlaylistEditor::renameCategory(const QString &category)
00969 {
00970     if (m_categorySelector->GetValue() == category)
00971         return;
00972 
00973     // change the category
00974     MSqlQuery query(MSqlQuery::InitCon());
00975     query.prepare("UPDATE music_smartplaylist_categories SET name = :NEW_CATEGORY "
00976                   "WHERE name = :OLD_CATEGORY;");
00977     query.bindValue(":OLD_CATEGORY", m_categorySelector->GetValue());
00978     query.bindValue(":NEW_CATEGORY", category);
00979 
00980     if (!query.exec())
00981         MythDB::DBError("Rename smartplaylist", query);
00982 
00983     if (!m_newPlaylist)
00984         m_originalCategory = m_categorySelector->GetValue();
00985 
00986     getSmartPlaylistCategories();
00987     m_categorySelector->SetValue(category);
00988 }
00989 
00990 QString SmartPlaylistEditor::getSQL(QString fields)
00991 {
00992     QString sql, whereClause, orderByClause, limitClause;
00993     sql = "SELECT " + fields + " FROM music_songs "
00994           "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
00995           "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
00996           "LEFT JOIN music_artists AS music_comp_artists ON music_albums.artist_id=music_comp_artists.artist_id "
00997           "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id ";
00998 
00999     whereClause = getWhereClause();
01000     orderByClause = getOrderByClause();
01001     if (m_limitSpin->GetIntValue() > 0)
01002         limitClause = " LIMIT " + m_limitSpin->GetValue();
01003 
01004     sql = sql + whereClause + orderByClause + limitClause;
01005 
01006     return sql;
01007 }
01008 
01009 QString SmartPlaylistEditor::getOrderByClause(void)
01010 {
01011     return getOrderBySQL(m_orderBySelector->GetValue());
01012 }
01013 
01014 QString SmartPlaylistEditor::getWhereClause(void)
01015 {
01016     bool bFirst = true;
01017     QString sql = "WHERE ";
01018 
01019     for (int x = 0; x <  m_criteriaRows.size(); x++)
01020     {
01021         QString criteria = m_criteriaRows[x]->getSQL();
01022         if (criteria.isEmpty())
01023             continue;
01024 
01025         if (bFirst)
01026         {
01027             sql += criteria;
01028             bFirst = false;
01029         }
01030         else
01031         {
01032             if (m_matchSelector->GetValue() == tr("Any"))
01033                 sql += " OR " + criteria;
01034             else
01035                 sql += " AND " + criteria;
01036         }
01037     }
01038 
01039     return sql;
01040 }
01041 
01042 void SmartPlaylistEditor::showResultsClicked(void)
01043 {
01044     QString sql = getSQL("song_id, music_artists.artist_name, album_name, "
01045                          "name, genre, music_songs.year, track");
01046 
01047     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
01048 
01049     SmartPLResultViewer *resultViewer = new SmartPLResultViewer(mainStack);
01050 
01051     if (!resultViewer->Create())
01052     {
01053         delete resultViewer;
01054         return;
01055     }
01056 
01057     resultViewer->setSQL(sql);
01058 
01059     mainStack->AddScreen(resultViewer);
01060 }
01061 
01062 void SmartPlaylistEditor::orderByClicked(void)
01063 {
01064     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01065 
01066     SmartPLOrderByDialog *orderByDialog = new SmartPLOrderByDialog(popupStack);
01067 
01068     if (!orderByDialog->Create())
01069     {
01070         delete orderByDialog;
01071         return;
01072     }
01073 
01074     orderByDialog->setFieldList(m_orderBySelector->GetValue());
01075 
01076     connect(orderByDialog, SIGNAL(orderByChanged(QString)), SLOT(orderByChanged(QString)));
01077 
01078     popupStack->AddScreen(orderByDialog);
01079 }
01080 
01081 void SmartPlaylistEditor::orderByChanged(QString orderBy)
01082 {
01083     if (m_orderBySelector->MoveToNamedPosition(orderBy))
01084         return;
01085 
01086     // not found so add it to the selector
01087     new MythUIButtonListItem(m_orderBySelector, orderBy);
01088     m_orderBySelector->SetValue(orderBy);
01089 }
01090 
01091 void SmartPlaylistEditor::getSmartPlaylistCategories(void)
01092 {
01093     m_categorySelector->Reset();
01094     MSqlQuery query(MSqlQuery::InitCon());
01095 
01096     if (query.exec("SELECT name FROM music_smartplaylist_categories ORDER BY name;"))
01097     {
01098         if (query.isActive() && query.size() > 0)
01099         {
01100             while (query.next())
01101                 new MythUIButtonListItem(m_categorySelector, query.value(0).toString());
01102         }
01103         else
01104         {
01105             LOG(VB_GENERAL, LOG_ERR,
01106                 "Could not find any smartplaylist categories");
01107         }
01108     }
01109     else
01110     {
01111         MythDB::DBError("Load smartplaylist categories", query);
01112     }
01113 }
01114 
01115 // static function to delete a smartplaylist and any associated smartplaylist items
01116 bool SmartPlaylistEditor::deleteSmartPlaylist(QString category, QString name)
01117 {
01118     // get categoryid
01119     int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
01120 
01121     MSqlQuery query(MSqlQuery::InitCon());
01122 
01123     // get playlist ID
01124     int ID;
01125     query.prepare("SELECT smartplaylistid FROM music_smartplaylists WHERE name = :NAME "
01126                   "AND categoryid = :CATEGORYID;");
01127     query.bindValue(":NAME", name);
01128     query.bindValue(":CATEGORYID", categoryid);
01129     if (query.exec())
01130     {
01131         if (query.isActive() && query.size() > 0)
01132         {
01133             query.first();
01134             ID = query.value(0).toInt();
01135         }
01136         else
01137         {
01138             // not always an error maybe we are trying to delete a playlist
01139             // that does not exist
01140             return true;
01141         }
01142     }
01143     else
01144     {
01145         MythDB::DBError("Delete smartplaylist", query);
01146         return false;
01147     }
01148 
01149     //delete smartplaylist items
01150     query.prepare("DELETE FROM music_smartplaylist_items WHERE smartplaylistid = :ID;");
01151     query.bindValue(":ID", ID);
01152     if (!query.exec())
01153         MythDB::DBError("Delete smartplaylist items", query);
01154 
01155     //delete smartplaylist
01156     query.prepare("DELETE FROM music_smartplaylists WHERE smartplaylistid = :ID;");
01157     query.bindValue(":ID", ID);
01158     if (!query.exec())
01159         MythDB::DBError("Delete smartplaylist", query);
01160 
01161     return true;
01162 }
01163 
01164 // static function to delete all smartplaylists belonging to the given category
01165 // will also delete any associated smartplaylist items
01166 bool SmartPlaylistEditor::deleteCategory(QString category)
01167 {
01168     int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
01169     MSqlQuery query(MSqlQuery::InitCon());
01170 
01171     //delete all smartplaylists with the selected category
01172     query.prepare("SELECT name FROM music_smartplaylists "
01173                   "WHERE categoryid = :CATEGORYID;");
01174     query.bindValue(":CATEGORYID", categoryid);
01175     if (!query.exec())
01176     {
01177         MythDB::DBError("Delete SmartPlaylist Category", query);
01178         return false;
01179     }
01180 
01181     if (query.isActive() && query.size() > 0)
01182     {
01183         while (query.next())
01184         {
01185             SmartPlaylistEditor::deleteSmartPlaylist(category, query.value(0).toString());
01186         }
01187     }
01188 
01189     // delete the category
01190     query.prepare("DELETE FROM music_smartplaylist_categories WHERE categoryid = :ID;");
01191     query.bindValue(":ID", categoryid);
01192     if (!query.exec())
01193         MythDB::DBError("Delete smartplaylist category", query);
01194 
01195     return true;
01196 }
01197 
01198 // static function to lookup the categoryid given its name
01199 int SmartPlaylistEditor::lookupCategoryID(QString category)
01200 {
01201     int ID;
01202     MSqlQuery query(MSqlQuery::InitCon());
01203     query.prepare("SELECT categoryid FROM music_smartplaylist_categories "
01204                   "WHERE name = :CATEGORY;");
01205     query.bindValue(":CATEGORY", category);
01206 
01207     if (query.exec())
01208     {
01209         if (query.isActive() && query.size() > 0)
01210         {
01211             query.first();
01212             ID = query.value(0).toInt();
01213         }
01214         else
01215         {
01216             LOG(VB_GENERAL, LOG_ERR,
01217                 QString("Failed to find smart playlist category: %1")
01218                     .arg(category));
01219             ID = -1;
01220         }
01221     }
01222     else
01223     {
01224         MythDB::DBError("Getting category ID", query);
01225         ID = -1;
01226     }
01227 
01228     return ID;
01229 }
01230 
01231 void  SmartPlaylistEditor::getCategoryAndName(QString &category, QString &name)
01232 {
01233     category = m_categorySelector->GetValue();
01234     name = m_titleEdit->GetText();
01235 }
01236 
01237 /*
01238 ---------------------------------------------------------------------
01239 */
01240 
01241 CriteriaRowEditor::CriteriaRowEditor(MythScreenStack* parent, SmartPLCriteriaRow* row)
01242                  : MythScreenType(parent, "CriteriaRowEditor"),
01243                 m_criteriaRow(NULL), m_fieldSelector(NULL),
01244                 m_operatorSelector(NULL), m_value1Edit(NULL),
01245                 m_value2Edit(NULL), m_value1Selector(NULL),
01246                 m_value2Selector(NULL), m_value1Spinbox(NULL),
01247                 m_value2Spinbox(NULL), m_value1Button(NULL),
01248                 m_value2Button(NULL), m_andText(NULL),
01249                 m_cancelButton(NULL), m_saveButton(NULL)
01250 {
01251     m_criteriaRow = row;
01252 }
01253 
01254 CriteriaRowEditor::~CriteriaRowEditor(void)
01255 {
01256 }
01257 
01258 bool CriteriaRowEditor::Create(void)
01259 {
01260     if (!LoadWindowFromXML("music-ui.xml", "criteriaroweditor", this))
01261         return false;
01262 
01263     bool err = false;
01264 
01265     UIUtilE::Assign(this, m_fieldSelector,     "fieldselector",    &err);
01266     UIUtilE::Assign(this, m_operatorSelector,  "operatorselector", &err);
01267     UIUtilE::Assign(this, m_value1Edit,        "value1edit",       &err);
01268     UIUtilE::Assign(this, m_value2Edit,        "value2edit",       &err);
01269     UIUtilE::Assign(this, m_value1Selector,    "value1selector",   &err);
01270     UIUtilE::Assign(this, m_value2Selector,    "value2selector",   &err);
01271     UIUtilE::Assign(this, m_value1Spinbox,     "value1spinbox",    &err);
01272     UIUtilE::Assign(this, m_value2Spinbox,     "value2spinbox",    &err);
01273     UIUtilE::Assign(this, m_value1Button,      "value1button",     &err);
01274     UIUtilE::Assign(this, m_value2Button,      "value2button",     &err);
01275     UIUtilE::Assign(this, m_cancelButton,      "cancelbutton",     &err);
01276     UIUtilE::Assign(this, m_saveButton,        "savebutton",       &err);
01277 
01278     if (err)
01279     {
01280         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'criteriaroweditor'");
01281         return false;
01282     }
01283 
01284     updateFields();
01285     updateOperators();
01286     updateValues();
01287 
01288     connect(m_fieldSelector, SIGNAL(itemSelected(MythUIButtonListItem*)), SLOT(fieldChanged()));
01289     connect(m_operatorSelector, SIGNAL(itemSelected(MythUIButtonListItem*)), SLOT(operatorChanged()));
01290 
01291     connect(m_value1Edit, SIGNAL(valueChanged()), SLOT(valueEditChanged()));
01292     connect(m_value2Edit, SIGNAL(valueChanged()), SLOT(valueEditChanged()));
01293     connect(m_value1Selector, SIGNAL(itemSelected(MythUIButtonListItem*)), SLOT(valueEditChanged()));
01294     connect(m_value2Selector, SIGNAL(itemSelected(MythUIButtonListItem*)), SLOT(valueEditChanged()));
01295 
01296     connect(m_value1Button, SIGNAL(Clicked()), SLOT(valueButtonClicked()));
01297     connect(m_value2Button, SIGNAL(Clicked()), SLOT(valueButtonClicked()));
01298 
01299     connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close()));
01300     connect(m_saveButton, SIGNAL(Clicked()), SLOT(saveClicked()));
01301 
01302     BuildFocusList();
01303 
01304     return true;
01305 }
01306 
01307 void CriteriaRowEditor::updateFields(void)
01308 {
01309     for (int x = 0; x < SmartPLFieldsCount; x++)
01310         new MythUIButtonListItem(m_fieldSelector, SmartPLFields[x].name);
01311 
01312     m_fieldSelector->SetValue(m_criteriaRow->Field);
01313 }
01314 
01315 void CriteriaRowEditor::updateOperators(void)
01316 {
01317     for (int x = 0; x < SmartPLOperatorsCount; x++)
01318         new MythUIButtonListItem(m_operatorSelector, SmartPLOperators[x].name);
01319 
01320     m_operatorSelector->SetValue(m_criteriaRow->Operator);
01321 }
01322 
01323 void CriteriaRowEditor::valueEditChanged(void)
01324 {
01325     enableSaveButton();
01326 }
01327 
01328 void CriteriaRowEditor::updateValues(void)
01329 {
01330     m_value1Edit->SetText(m_criteriaRow->Value1);
01331     m_value2Edit->SetText(m_criteriaRow->Value2);
01332     m_value1Spinbox->SetValue(m_criteriaRow->Value1);
01333     m_value2Spinbox->SetValue(m_criteriaRow->Value2);
01334 
01335     if (!m_value1Selector->MoveToNamedPosition(m_criteriaRow->Value1))
01336     {
01337         // not found so add it to the selector
01338         new MythUIButtonListItem(m_value1Selector, m_criteriaRow->Value1);
01339         m_value1Selector->SetValue(m_criteriaRow->Value1);
01340     }
01341 
01342     if (!m_value2Selector->MoveToNamedPosition(m_criteriaRow->Value2))
01343     {
01344         // not found so add it to the selector
01345         new MythUIButtonListItem(m_value2Selector, m_criteriaRow->Value2);
01346         m_value2Selector->SetValue(m_criteriaRow->Value2);
01347     }
01348 }
01349 
01350 void CriteriaRowEditor::saveClicked()
01351 {
01352     SmartPLField *Field;
01353     Field = lookupField(m_fieldSelector->GetValue());
01354     if (!Field)
01355         return;
01356 
01357     m_criteriaRow->Field = m_fieldSelector->GetValue();
01358     m_criteriaRow->Operator = m_operatorSelector->GetValue();
01359 
01360     if (Field->type == ftNumeric)
01361     {
01362         m_criteriaRow->Value1 = m_value1Spinbox->GetValue();
01363         m_criteriaRow->Value2 = m_value2Spinbox->GetValue();
01364     }
01365     else if (Field->type == ftBoolean || Field->type == ftDate)
01366     {
01367         m_criteriaRow->Value1 = m_value1Selector->GetValue();
01368         m_criteriaRow->Value2 = m_value2Selector->GetValue();
01369     }
01370     else // ftString
01371     {
01372         m_criteriaRow->Value1 = m_value1Edit->GetText();
01373         m_criteriaRow->Value2 = m_value2Edit->GetText();
01374     }
01375 
01376     emit criteriaChanged();
01377 
01378     Close();
01379 }
01380 
01381 void CriteriaRowEditor::enableSaveButton()
01382 {
01383     bool enabled = false;
01384 
01385     SmartPLField *Field;
01386     Field = lookupField(m_fieldSelector->GetValue());
01387 
01388     SmartPLOperator *Operator;
01389     Operator = lookupOperator(m_operatorSelector->GetValue());
01390 
01391     if (Field && Operator)
01392     {
01393         if (Field->type == ftNumeric || Field->type == ftBoolean)
01394             enabled = true;
01395         else if (Field->type == ftDate)
01396         {
01397             if (Operator->noOfArguments == 0)
01398                 enabled = true;
01399             else if (Operator->noOfArguments == 1 && !m_value1Selector->GetValue().isEmpty())
01400                 enabled = true;
01401             else if (Operator->noOfArguments == 2 && !m_value1Selector->GetValue().isEmpty()
01402                                                   && !m_value2Selector->GetValue().isEmpty())
01403                 enabled = true;
01404         }
01405         else // ftString
01406         {
01407             if (Operator->noOfArguments == 0)
01408                 enabled = true;
01409             else if (Operator->noOfArguments == 1 && !m_value1Edit->GetText().isEmpty())
01410                 enabled = true;
01411             else if (Operator->noOfArguments == 2 && !m_value1Edit->GetText().isEmpty()
01412                                                   && !m_value2Edit->GetText().isEmpty())
01413                 enabled = true;
01414         }
01415     }
01416 
01417     m_saveButton->SetEnabled(enabled);
01418 }
01419 
01420 void CriteriaRowEditor::fieldChanged(void)
01421 {
01422     SmartPLField *Field;
01423     Field = lookupField(m_fieldSelector->GetValue());
01424     if (!Field)
01425         return;
01426 
01427     if (Field->type == ftBoolean)
01428     {
01429         // add yes / no items to combo
01430         m_value1Selector->Reset();
01431         new MythUIButtonListItem(m_value1Selector, "No");
01432         new MythUIButtonListItem(m_value1Selector, "Yes");
01433         m_value2Selector->Reset();
01434         new MythUIButtonListItem(m_value2Selector, "No");
01435         new MythUIButtonListItem(m_value2Selector, "Yes");
01436     }
01437     else if (Field->type == ftDate)
01438     {
01439         // add a couple of date values to the combo
01440         m_value1Selector->Reset();
01441         new MythUIButtonListItem(m_value1Selector, "$DATE");
01442         new MythUIButtonListItem(m_value1Selector, "$DATE - 30 days");
01443         new MythUIButtonListItem(m_value1Selector, "$DATE - 60 days");
01444 
01445         if (!m_value1Selector->MoveToNamedPosition(m_criteriaRow->Value1))
01446         {
01447             // not found so add it to the selector
01448             new MythUIButtonListItem(m_value1Selector, m_criteriaRow->Value1);
01449             m_value1Selector->SetValue(m_criteriaRow->Value1);
01450         }
01451 
01452 
01453         m_value2Selector->Reset();
01454         new MythUIButtonListItem(m_value2Selector, "$DATE");
01455         new MythUIButtonListItem(m_value2Selector, "$DATE - 30 days");
01456         new MythUIButtonListItem(m_value2Selector, "$DATE - 60 days");
01457 
01458         if (!m_value2Selector->MoveToNamedPosition(m_criteriaRow->Value2))
01459         {
01460             // not found so add it to the selector
01461             new MythUIButtonListItem(m_value2Selector, m_criteriaRow->Value2);
01462             m_value2Selector->SetValue(m_criteriaRow->Value2);
01463         }
01464     }
01465 
01466     // get list of operators valid for this field type
01467     getOperatorList(Field->type);
01468 
01469     enableSaveButton();
01470 }
01471 
01472 void CriteriaRowEditor::operatorChanged(void)
01473 {
01474     SmartPLField *Field;
01475     Field = lookupField(m_fieldSelector->GetValue());
01476     if (!Field)
01477         return;
01478 
01479     SmartPLOperator *Operator;
01480     Operator = lookupOperator(m_operatorSelector->GetValue());
01481     if (!Operator)
01482         return;
01483 
01484     // hide all widgets
01485     m_value1Edit->Hide();
01486     m_value2Edit->Hide();
01487     m_value1Button->Hide();
01488     m_value2Button->Hide();
01489     m_value1Selector->Hide();
01490     m_value2Selector->Hide();
01491     m_value1Spinbox->Hide();
01492     m_value2Spinbox->Hide();
01493 
01494     // show spin edits
01495     if (Field->type == ftNumeric)
01496     {
01497         if (Operator->noOfArguments >= 1)
01498         {
01499             m_value1Spinbox->Show();
01500             int currentValue = m_value1Spinbox->GetIntValue();
01501             m_value1Spinbox->SetRange(Field->minValue, Field->maxValue, 1);
01502 
01503             if (currentValue < Field->minValue || currentValue > Field->maxValue)
01504                 m_value1Spinbox->SetValue(Field->defaultValue);
01505         }
01506 
01507         if (Operator->noOfArguments == 2)
01508         {
01509             m_value2Spinbox->Show();
01510             int currentValue = m_value2Spinbox->GetIntValue();
01511             m_value2Spinbox->SetRange(Field->minValue, Field->maxValue, 1);
01512 
01513             if (currentValue < Field->minValue || currentValue > Field->maxValue)
01514                 m_value2Spinbox->SetValue(Field->defaultValue);
01515         }
01516     }
01517     else if (Field->type == ftBoolean)
01518     {
01519         // only show value1combo
01520         m_value1Selector->Show();
01521     }
01522     else if (Field->type == ftDate)
01523     {
01524         if (Operator->noOfArguments >= 1)
01525         {
01526             m_value1Selector->Show();
01527             m_value1Button->Show();
01528         }
01529 
01530         if (Operator->noOfArguments == 2)
01531         {
01532             m_value2Selector->Show();
01533             m_value2Button->Show();
01534         }
01535     }
01536     else // ftString
01537     {
01538         if (Operator->noOfArguments >= 1)
01539         {
01540             m_value1Edit->Show();
01541             m_value1Button->Show();
01542         }
01543 
01544         if (Operator->noOfArguments == 2)
01545         {
01546             m_value2Edit->Show();
01547             m_value2Button->Show();
01548         }
01549     }
01550 
01551     enableSaveButton();
01552 }
01553 
01554 void CriteriaRowEditor::getOperatorList(SmartPLFieldType fieldType)
01555 {
01556     QString currentOperator = m_operatorSelector->GetValue();
01557 
01558     m_operatorSelector->Reset();
01559 
01560     for (int x = 0; x < SmartPLOperatorsCount; x++)
01561     {
01562         // don't add operators that only work with string fields
01563         if (fieldType != ftString && SmartPLOperators[x].stringOnly)
01564             continue;
01565 
01566         // don't add operators that only work with boolean fields
01567         if (fieldType == ftBoolean && !SmartPLOperators[x].validForBoolean)
01568             continue;
01569 
01570         new MythUIButtonListItem(m_operatorSelector, SmartPLOperators[x].name);
01571     }
01572 
01573     // try to set the operatorCombo to the same operator or else the first item
01574     m_operatorSelector->SetValue(currentOperator);
01575 }
01576 
01577 void CriteriaRowEditor::valueButtonClicked(void)
01578 {
01579     QString msg;
01580     QStringList searchList;
01581     QString s = GetFocusWidget() == m_value1Button ? m_value1Edit->GetText() : m_value2Edit->GetText();
01582 
01583     if (m_fieldSelector->GetValue() == "Artist")
01584     {
01585         msg = tr("Select an Artist");
01586         searchList = Metadata::fillFieldList("artist");
01587     }
01588     else if (m_fieldSelector->GetValue() == "Comp. Artist")
01589     {
01590         msg = tr("Select a Compilation Artist");
01591         searchList = Metadata::fillFieldList("compilation_artist");
01592     }
01593     else if (m_fieldSelector->GetValue() == "Album")
01594     {
01595         msg = tr("Select an Album");
01596         searchList = Metadata::fillFieldList("album");
01597     }
01598     else if (m_fieldSelector->GetValue() == "Genre")
01599     {
01600         msg = tr("Select a Genre");
01601         searchList = Metadata::fillFieldList("genre");
01602     }
01603     else if (m_fieldSelector->GetValue() == "Title")
01604     {
01605         msg = tr("Select a Title");
01606         searchList = Metadata::fillFieldList("title");
01607     }
01608     else if (m_fieldSelector->GetValue() == "Last Play")
01609     {
01610         editDate();
01611         return;
01612     }
01613     else if (m_fieldSelector->GetValue() == "Date Imported")
01614     {
01615         editDate();
01616         return;
01617     }
01618 
01619     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01620     MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, s);
01621 
01622     if (!searchDlg->Create())
01623     {
01624         delete searchDlg;
01625         return;
01626     }
01627 
01628     connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setValue(QString)));
01629 
01630     popupStack->AddScreen(searchDlg);
01631 }
01632 
01633 void CriteriaRowEditor::setValue(QString value)
01634 {
01635     if (GetFocusWidget() && GetFocusWidget() == m_value1Button)
01636         m_value1Edit->SetText(value);
01637     else
01638         m_value2Edit->SetText(value);
01639 }
01640 
01641 void CriteriaRowEditor::editDate(void)
01642 {
01643     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01644     SmartPLDateDialog *dateDlg = new SmartPLDateDialog(popupStack);
01645     QString date = GetFocusWidget() == m_value1Button ? m_value1Selector->GetValue() : m_value2Selector->GetValue();
01646 
01647     if (!dateDlg->Create())
01648     {
01649         delete dateDlg;
01650         return;
01651     }
01652 
01653     dateDlg->setDate(date);
01654 
01655     connect(dateDlg, SIGNAL(dateChanged(QString)), SLOT(setDate(QString)));
01656 
01657     popupStack->AddScreen(dateDlg);
01658 }
01659 
01660 void CriteriaRowEditor::setDate(QString date)
01661 {
01662     if (GetFocusWidget() && GetFocusWidget() == m_value1Button)
01663     {
01664         if (m_value1Selector->MoveToNamedPosition(date))
01665             return;
01666 
01667         // not found so add it to the selector
01668         new MythUIButtonListItem(m_value1Selector, date);
01669         m_value1Selector->SetValue(date);
01670     }
01671     else
01672     {
01673         if (m_value2Selector->MoveToNamedPosition(date))
01674             return;
01675 
01676         // not found so add it to the selector
01677         new MythUIButtonListItem(m_value2Selector, date);
01678         m_value2Selector->SetValue(date);
01679     }
01680 }
01681 
01682 /*
01683 ---------------------------------------------------------------------
01684 */
01685 
01686 
01687 SmartPLResultViewer::SmartPLResultViewer(MythScreenStack *parent)
01688                    : MythScreenType(parent, "SmartPLResultViewer"),
01689                    m_trackList(NULL), m_positionText(NULL)
01690 {
01691 }
01692 
01693 SmartPLResultViewer::~SmartPLResultViewer()
01694 {
01695 }
01696 
01697 bool SmartPLResultViewer::Create(void)
01698 {
01699     if (!LoadWindowFromXML("music-ui.xml", "smartplresultviewer", this))
01700         return false;
01701 
01702     bool err = false;
01703 
01704     UIUtilE::Assign(this, m_trackList, "tracklist", &err);
01705     UIUtilW::Assign(this, m_positionText, "position", &err);
01706 
01707     if (err)
01708     {
01709         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'smartplresultviewer'");
01710         return false;
01711     }
01712 
01713     connect(m_trackList, SIGNAL(itemVisible(MythUIButtonListItem*)),
01714             this, SLOT(trackVisible(MythUIButtonListItem*)));
01715     connect(m_trackList, SIGNAL(itemSelected(MythUIButtonListItem*)),
01716             this, SLOT(trackSelected(MythUIButtonListItem*)));
01717 
01718     BuildFocusList();
01719 
01720     return true;
01721 }
01722 
01723 bool SmartPLResultViewer::keyPressEvent(QKeyEvent *event)
01724 {
01725     if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
01726         return true;
01727 
01728     bool handled = false;
01729     QStringList actions;
01730     handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
01731 
01732     for (int i = 0; i < actions.size() && !handled; i++)
01733     {
01734         QString action = actions[i];
01735         handled = true;
01736 
01737         if (action == "INFO")
01738             showTrackInfo();
01739         else
01740             handled = false;
01741     }
01742 
01743     if (!handled && MythScreenType::keyPressEvent(event))
01744         handled = true;
01745 
01746     return handled;
01747 }
01748 
01749 void SmartPLResultViewer::trackVisible(MythUIButtonListItem *item)
01750 {
01751     if (!item)
01752         return;
01753 
01754     if (item->GetImage().isEmpty())
01755     {
01756         Metadata *mdata = qVariantValue<Metadata*> (item->GetData());
01757         if (mdata)
01758         {
01759             QString artFile = mdata->getAlbumArtFile();
01760             if (artFile.isEmpty())
01761                 item->SetImage("mm_nothumb.png");
01762             else
01763                 item->SetImage(mdata->getAlbumArtFile());
01764         }
01765         else
01766             item->SetImage("mm_nothumb.png");
01767     }
01768 }
01769 
01770 void SmartPLResultViewer::trackSelected(MythUIButtonListItem *item)
01771 {
01772     if (!item || !m_positionText)
01773         return;
01774 
01775     m_positionText->SetText(QString(tr("%1 of %2"))
01776                             .arg(m_trackList->GetCurrentPos() + 1)
01777                             .arg(m_trackList->GetCount()));
01778 }
01779 void SmartPLResultViewer::showTrackInfo(void)
01780 {
01781     MythUIButtonListItem *item = m_trackList->GetItemCurrent();
01782     if (!item)
01783         return;
01784 
01785     Metadata *mdata = qVariantValue<Metadata*> (item->GetData());
01786     if (!mdata)
01787         return;
01788 
01789     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01790 
01791     TrackInfoDialog *dlg = new TrackInfoDialog(popupStack, mdata, "trackinfopopup");
01792 
01793     if (!dlg->Create())
01794     {
01795         delete dlg;
01796         return;
01797     }
01798 
01799     popupStack->AddScreen(dlg);
01800 }
01801 
01802 void SmartPLResultViewer::setSQL(QString sql)
01803 {
01804     m_trackList->Reset();;
01805 
01806     MSqlQuery query(MSqlQuery::InitCon());
01807 
01808     if (query.exec(sql))
01809     {
01810         while (query.next())
01811         {
01812             Metadata *mdata = gMusicData->all_music->getMetadata(query.value(0).toInt());
01813             if (mdata)
01814             {
01815                 MetadataMap metadataMap;
01816                 mdata->toMap(metadataMap);
01817 
01818                 MythUIButtonListItem *item = new MythUIButtonListItem(m_trackList, "", qVariantFromValue(mdata));
01819                 item->SetTextFromMap(metadataMap);
01820             }
01821         }
01822     }
01823 
01824     trackSelected(m_trackList->GetItemCurrent());
01825 }
01826 
01827 
01828 /*
01829 ---------------------------------------------------------------------
01830 */
01831 
01832 SmartPLOrderByDialog::SmartPLOrderByDialog(MythScreenStack *parent)
01833                  :MythScreenType(parent, "SmartPLOrderByDialog"),
01834         m_fieldList(NULL), m_orderSelector(NULL), m_addButton(NULL),
01835         m_deleteButton(NULL), m_moveUpButton(NULL), m_moveDownButton(NULL),
01836         m_ascendingButton(NULL), m_descendingButton(NULL), m_cancelButton(NULL),
01837         m_okButton(NULL)
01838 {
01839 }
01840 
01841 SmartPLOrderByDialog::~SmartPLOrderByDialog(void)
01842 {
01843 }
01844 
01845 bool SmartPLOrderByDialog::Create(void)
01846 {
01847     if (!LoadWindowFromXML("music-ui.xml", "orderbydialog", this))
01848         return false;
01849 
01850     bool err = false;
01851 
01852     UIUtilE::Assign(this, m_fieldList,        "fieldlist",        &err);
01853     UIUtilE::Assign(this, m_orderSelector,    "fieldselector",    &err);
01854     UIUtilE::Assign(this, m_addButton,        "addbutton",        &err);
01855     UIUtilE::Assign(this, m_deleteButton,     "deletebutton",     &err);
01856     UIUtilE::Assign(this, m_moveUpButton,     "moveupbutton",     &err);
01857     UIUtilE::Assign(this, m_moveDownButton,   "movedownbutton",   &err);
01858     UIUtilE::Assign(this, m_ascendingButton,  "ascendingbutton",  &err);
01859     UIUtilE::Assign(this, m_descendingButton, "descendingbutton", &err);
01860     UIUtilE::Assign(this, m_cancelButton,     "cancelbutton",     &err);
01861     UIUtilE::Assign(this, m_okButton,         "okbutton",         &err);
01862 
01863     if (err)
01864     {
01865         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'orderbydialog'");
01866         return false;
01867     }
01868 
01869     connect(m_addButton, SIGNAL(Clicked()), this, SLOT(addPressed()));
01870     connect(m_deleteButton, SIGNAL(Clicked()), this, SLOT(deletePressed()));
01871     connect(m_moveUpButton, SIGNAL(Clicked()), this, SLOT(moveUpPressed()));
01872     connect(m_moveDownButton, SIGNAL(Clicked()), this, SLOT(moveDownPressed()));
01873     connect(m_ascendingButton, SIGNAL(Clicked()), this, SLOT(ascendingPressed()));
01874     connect(m_descendingButton, SIGNAL(Clicked()), this, SLOT(descendingPressed()));
01875     connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
01876     connect(m_okButton, SIGNAL(Clicked()), this, SLOT(okPressed()));
01877 
01878     connect(m_orderSelector, SIGNAL(itemSelected(MythUIButtonListItem*)),
01879             this, SLOT(orderByChanged(void)));
01880     connect(m_fieldList, SIGNAL(itemSelected(MythUIButtonListItem*)),
01881             this, SLOT(fieldListSelectionChanged(MythUIButtonListItem*)));
01882 
01883     getOrderByFields();
01884 
01885     orderByChanged();
01886 
01887     BuildFocusList();
01888 
01889     return true;
01890 }
01891 
01892 QString SmartPLOrderByDialog::getFieldList(void)
01893 {
01894     QString result;
01895     bool bFirst = true;
01896 
01897     for (int i = 0; i < m_fieldList->GetCount(); i++)
01898     {
01899         if (bFirst)
01900         {
01901             bFirst = false;
01902             result = m_fieldList->GetItemAt(i)->GetText();
01903         }
01904         else
01905             result += ", " + m_fieldList->GetItemAt(i)->GetText();
01906     }
01907 
01908     return result;
01909 }
01910 
01911 void SmartPLOrderByDialog::setFieldList(const QString &fieldList)
01912 {
01913     m_fieldList->Reset();
01914     QStringList list = fieldList.split(",");
01915 
01916     for (int x = 0; x < list.count(); x++)
01917     {
01918         MythUIButtonListItem *item = new MythUIButtonListItem(m_fieldList, list[x].trimmed());
01919         QString state = list[x].contains("(A)") ? "ascending" : "descending";
01920         item->DisplayState(state, "sortstate");
01921     }
01922 
01923     orderByChanged();
01924 }
01925 
01926 void SmartPLOrderByDialog::fieldListSelectionChanged(MythUIButtonListItem *item)
01927 {
01928     if (!item)
01929         return;
01930 
01931     m_orderSelector->SetValue(item->GetText().left(item->GetText().length() - 4));
01932 }
01933 
01934 void SmartPLOrderByDialog::ascendingPressed(void)
01935 {
01936     if (!m_fieldList->GetItemCurrent())
01937         return;
01938 
01939     m_fieldList->GetItemCurrent()->SetText(m_orderSelector->GetValue() + " (A)");
01940     m_fieldList->GetItemCurrent()->DisplayState("ascending", "sortstate");
01941 
01942     orderByChanged();
01943     SetFocusWidget(m_descendingButton);
01944 }
01945 
01946 void SmartPLOrderByDialog::descendingPressed(void)
01947 {
01948     if (!m_fieldList->GetItemCurrent())
01949         return;
01950 
01951     m_fieldList->GetItemCurrent()->SetText(m_orderSelector->GetValue() + " (D)");
01952     m_fieldList->GetItemCurrent()->DisplayState("descending", "sortstate");
01953 
01954     orderByChanged();
01955     SetFocusWidget(m_ascendingButton);
01956 }
01957 
01958 void SmartPLOrderByDialog::addPressed(void)
01959 {
01960     MythUIButtonListItem *item = new MythUIButtonListItem(m_fieldList, m_orderSelector->GetValue() + " (A)");
01961     item->DisplayState("ascending", "sortstate");
01962 
01963     orderByChanged();
01964     SetFocusWidget(m_orderSelector);
01965 }
01966 
01967 void SmartPLOrderByDialog::deletePressed(void)
01968 {
01969     m_fieldList->RemoveItem(m_fieldList->GetItemCurrent());
01970     orderByChanged();
01971 
01972     if (!m_deleteButton->IsEnabled())
01973         SetFocusWidget(m_addButton);
01974     else
01975         SetFocusWidget(m_deleteButton);
01976 }
01977 
01978 void SmartPLOrderByDialog::moveUpPressed(void)
01979 {
01980     MythUIButtonListItem *item = m_fieldList->GetItemCurrent();
01981 
01982     if (item)
01983         item->MoveUpDown(true);
01984 
01985     orderByChanged();
01986 
01987     if (!m_moveUpButton->IsEnabled())
01988         SetFocusWidget(m_moveDownButton);
01989     else
01990         SetFocusWidget(m_moveUpButton);
01991 }
01992 
01993 void SmartPLOrderByDialog::moveDownPressed(void)
01994 {
01995     MythUIButtonListItem *item = m_fieldList->GetItemCurrent();
01996 
01997     if (item)
01998         item->MoveUpDown(false);
01999 
02000     orderByChanged();
02001 
02002     if (!m_moveDownButton->IsEnabled())
02003         SetFocusWidget(m_moveUpButton);
02004     else
02005         SetFocusWidget(m_moveDownButton);
02006 }
02007 
02008 void SmartPLOrderByDialog::okPressed(void)
02009 {
02010     emit orderByChanged(getFieldList());
02011     Close();
02012 }
02013 
02014 void SmartPLOrderByDialog::orderByChanged(void)
02015 {
02016     bool found = false;
02017     for (int i = 0 ; i < m_fieldList->GetCount() ; ++i)
02018     {
02019         if (m_fieldList->GetItemAt(i)->GetText().startsWith(m_orderSelector->GetValue()))
02020         {
02021             m_fieldList->SetItemCurrent(i);
02022             found = true;
02023         }
02024     }
02025 
02026     if (found)
02027     {
02028         m_addButton->SetEnabled(false);
02029         m_deleteButton->SetEnabled(true);
02030         m_moveUpButton->SetEnabled((m_fieldList->GetCurrentPos() != 0));
02031         m_moveDownButton->SetEnabled((m_fieldList->GetCurrentPos() != m_fieldList->GetCount() - 1) );
02032         m_ascendingButton->SetEnabled((m_fieldList->GetValue().right(3) == "(D)") );
02033         m_descendingButton->SetEnabled((m_fieldList->GetValue().right(3) == "(A)"));
02034     }
02035     else
02036     {
02037         m_addButton->SetEnabled(true);
02038         m_deleteButton->SetEnabled(false);
02039         m_moveUpButton->SetEnabled(false);
02040         m_moveDownButton->SetEnabled(false);
02041         m_ascendingButton->SetEnabled(false);
02042         m_descendingButton->SetEnabled(false);
02043     }
02044 }
02045 
02046 void SmartPLOrderByDialog::getOrderByFields(void)
02047 {
02048     m_orderSelector->Reset();
02049     for (int x = 1; x < SmartPLFieldsCount; x++)
02050         new MythUIButtonListItem(m_orderSelector, SmartPLFields[x].name);
02051 }
02052 
02053 #if 0
02054 /*
02055 ---------------------------------------------------------------------
02056 */
02057 
02058 SmartPlaylistDialog::SmartPlaylistDialog(MythMainWindow *parent, const char *name)
02059                  :MythPopupBox(parent, name)
02060 {
02061     bool keyboard_accelerators = gCoreContext->GetNumSetting("KeyboardAccelerators", 1);
02062 
02063     // we have to create a parentless layout because otherwise MythPopupbox
02064     // complains about already having a layout
02065     vbox = new Q3VBoxLayout((QWidget *) 0, (int)(10 * hmult));
02066 
02067     Q3HBoxLayout *hbox = new Q3HBoxLayout(vbox, (int)(10 * wmult));
02068 
02069     // create the widgets
02070 
02071     caption = new QLabel(QString(tr("Smart Playlists")), this);
02072     QFont font = caption->font();
02073     font.setPointSize(int (font.pointSize() * 1.2));
02074     font.setBold(true);
02075     caption->setFont(font);
02076     caption->setPaletteForegroundColor(QColor("yellow"));
02077     caption->setBackgroundOrigin(ParentOrigin);
02078     caption->setAlignment(Qt::AlignCenter);
02079     caption->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
02080     caption->setMinimumWidth((int)(600 * hmult));
02081     caption->setMaximumWidth((int)(600 * hmult));
02082     hbox->addWidget(caption);
02083 
02084     // category
02085     hbox = new Q3HBoxLayout(vbox, (int)(10 * hmult));
02086     categoryCombo = new MythComboBox(false, this, "categoryCombo");
02087     categoryCombo->setFocus();
02088     connect(categoryCombo, SIGNAL(highlighted(int)), this, SLOT(categoryChanged(void)));
02089     connect(categoryCombo, SIGNAL(activated(int)), this, SLOT(categoryChanged(void)));
02090     hbox->addWidget(categoryCombo);
02091     getSmartPlaylistCategories();
02092 
02093     // listbox
02094     hbox = new Q3HBoxLayout(vbox, (int)(5 * hmult));
02095     listbox = new Q3MythListBox(this);
02096     listbox->setScrollBar(false);
02097     listbox->setBottomScrollBar(false);
02098     hbox->addWidget(listbox);
02099 
02100     hbox = new Q3HBoxLayout(vbox, (int)(5 * wmult));
02101     selectButton = new MythPushButton(this, "selectbutton");
02102     if (keyboard_accelerators)
02103         selectButton->setText(tr("1 Select"));
02104     else
02105         selectButton->setText(tr("Select"));
02106     hbox->addWidget(selectButton);
02107 
02108     newButton = new MythPushButton(this, "newbutton");
02109     if (keyboard_accelerators)
02110         newButton->setText(tr("2 New"));
02111     else
02112         newButton->setText(tr("New"));
02113     hbox->addWidget(newButton);
02114 
02115     hbox = new Q3HBoxLayout(vbox, (int)(5 * wmult));
02116     editButton = new MythPushButton(this, "editbutton");
02117     if (keyboard_accelerators)
02118         editButton->setText(tr("3 Edit"));
02119     else
02120         editButton->setText(tr("Edit"));
02121     hbox->addWidget(editButton);
02122 
02123     deleteButton = new MythPushButton(this, "deletebutton");
02124     if (keyboard_accelerators)
02125         deleteButton->setText(tr("4 Delete"));
02126     else
02127         deleteButton->setText(tr("Delete"));
02128     hbox->addWidget(deleteButton);
02129 
02130     addLayout(vbox);
02131 
02132     connect(newButton, SIGNAL(clicked()), this, SLOT(newPressed()));
02133     connect(editButton, SIGNAL(clicked()), this, SLOT(editPressed()));
02134     connect(deleteButton, SIGNAL(clicked()), this, SLOT(deletePressed()));
02135     connect(selectButton, SIGNAL(clicked()), this, SLOT(selectPressed()));
02136 
02137     categoryChanged();
02138 }
02139 
02140 void SmartPlaylistDialog::setSmartPlaylist(QString Category, QString Name)
02141 {
02142     // try to set the current playlist
02143     for (int x = 0; x < categoryCombo->count(); x++)
02144     {
02145         if (categoryCombo->text(x) == Category)
02146         {
02147             categoryCombo->setCurrentItem(x);
02148             categoryChanged();
02149             listbox->setCurrentItem(Name);
02150             listbox->setFocus();
02151             return;
02152         }
02153     }
02154 
02155     // can't find the smartplaylist just select the first item
02156     categoryCombo->setCurrentItem(0);
02157     listbox->setCurrentItem(0);
02158 }
02159 
02160 SmartPlaylistDialog::~SmartPlaylistDialog(void)
02161 {
02162     if (vbox)
02163     {
02164         delete vbox;
02165         vbox = NULL;
02166     }
02167 }
02168 
02169 void SmartPlaylistDialog::keyPressEvent(QKeyEvent *e)
02170 {
02171     bool handled = false;
02172     QStringList actions;
02173     handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
02174 
02175     for (int i = 0; i < actions.size() && !handled; i++)
02176     {
02177         QString action = actions[i];
02178         if (action == "ESCAPE")
02179         {
02180             handled = true;
02181             reject();
02182         }
02183         else if (action == "LEFT")
02184         {
02185             handled = true;
02186             focusNextPrevChild(false);
02187         }
02188         else if (action == "RIGHT")
02189         {
02190             handled = true;
02191             focusNextPrevChild(true);
02192         }
02193         else if (action == "UP")
02194         {
02195             handled = true;
02196             focusNextPrevChild(false);
02197         }
02198         else if (action == "DOWN")
02199         {
02200             handled = true;
02201             focusNextPrevChild(true);
02202         }
02203         else if (action == "1")
02204         {
02205             handled = true;
02206             selectPressed();
02207         }
02208         else if (action == "2")
02209         {
02210             handled = true;
02211             newPressed();
02212         }
02213         else if (action == "3")
02214         {
02215             handled = true;
02216             editPressed();
02217         }
02218         else if (action == "4")
02219         {
02220             handled = true;
02221             deletePressed();
02222         }
02223         else if (action == "SELECT" && listbox->hasFocus())
02224         {
02225             handled = true;
02226             selectPressed();
02227         }
02228 
02229     }
02230 
02231     if (!handled)
02232         MythPopupBox::keyPressEvent(e);
02233 }
02234 
02235 void SmartPlaylistDialog::newPressed(void)
02236 {
02237 #if 0
02238     SmartPlaylistEditor* editor = new SmartPlaylistEditor(GetMythMainWindow(), "SmartPlaylistEditor");
02239     editor->newSmartPlaylist(categoryCombo->currentText());
02240 
02241     editor->exec();
02242     QString category;
02243     QString name;
02244     editor->getCategoryAndName(category, name);
02245 
02246     delete editor;
02247 
02248     getSmartPlaylistCategories();
02249 
02250     // try to select the correct category and name
02251     categoryCombo->setCurrentText(category);
02252     categoryChanged();
02253     listbox->setCurrentItem(name);
02254     listbox->setFocus();
02255 #endif
02256 }
02257 
02258 void SmartPlaylistDialog::selectPressed(void)
02259 {
02260     accept();
02261 }
02262 
02263 void SmartPlaylistDialog::deletePressed(void)
02264 {
02265     if (!listbox->selectedItem())
02266         return;
02267 
02268     QString category = categoryCombo->currentText();
02269     QString name = listbox->selectedItem()->text();
02270 
02271     if (!MythPopupBox::showOkCancelPopup(GetMythMainWindow(),
02272             "Delete SmartPlaylist",
02273             tr("Are you sure you want to delete this SmartPlaylist?")
02274             + "\n\n\"" + name + "\"", false))
02275     {
02276         deleteButton->setFocus();
02277         return;
02278     }
02279 
02280     SmartPlaylistEditor::deleteSmartPlaylist(category, name);
02281 
02282     //refresh lists
02283     getSmartPlaylistCategories();
02284     categoryCombo->setCurrentText(category);
02285     categoryChanged();
02286 
02287     if (listbox->count() > 0)
02288         deleteButton->setFocus();
02289     else
02290         newButton->setFocus();
02291 }
02292 
02293 void SmartPlaylistDialog::editPressed(void)
02294 {
02295 #if 0
02296     QString category = categoryCombo->currentText();
02297     QString name = listbox->currentText();
02298 
02299     SmartPlaylistEditor* editor = new SmartPlaylistEditor(GetMythMainWindow(), "SmartPlaylistEditor");
02300     editor->editSmartPlaylist(category, name);
02301 
02302     editor->exec();
02303     editor->getCategoryAndName(category, name);
02304     getSmartPlaylistCategories();
02305     categoryChanged();
02306 
02307     delete editor;
02308 
02309     // try to select the correct category and name
02310     categoryCombo->setCurrentText(category);
02311     listbox->setCurrentItem(name);
02312     listbox->setFocus();
02313 #endif
02314 }
02315 
02316 void SmartPlaylistDialog::categoryChanged(void)
02317 {
02318     getSmartPlaylists(categoryCombo->currentText());
02319 }
02320 
02321 void SmartPlaylistDialog::getSmartPlaylistCategories(void)
02322 {
02323     categoryCombo->clear();
02324     MSqlQuery query(MSqlQuery::InitCon());
02325 
02326     if (query.exec("SELECT name FROM music_smartplaylist_categories ORDER BY name;"))
02327     {
02328         if (query.isActive() && query.size() > 0)
02329         {
02330             while (query.next())
02331                 categoryCombo->insertItem(query.value(0).toString());
02332         }
02333     }
02334     else
02335     {
02336         MythDB::DBError("Load smartplaylist categories", query);
02337     }
02338 }
02339 
02340 void SmartPlaylistDialog::getSmartPlaylists(QString category)
02341 {
02342     int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
02343 
02344     listbox->clear();
02345 
02346     MSqlQuery query(MSqlQuery::InitCon());
02347     query.prepare("SELECT name FROM music_smartplaylists WHERE categoryid = :CATEGORYID "
02348                   "ORDER BY name;");
02349     query.bindValue(":CATEGORYID", categoryid);
02350                        if (query.exec())
02351     {
02352         if (query.isActive() && query.size() > 0)
02353         {
02354             while (query.next())
02355             {
02356                 listbox->insertItem(query.value(0).toString());
02357             }
02358 
02359             listbox->setCurrentItem(0);
02360             listbox->setTopItem(0);
02361         }
02362     }
02363     else
02364         MythDB::DBError("Load smartplaylist names", query);
02365 
02366 
02367     deleteButton->setEnabled( (listbox->count() > 0) );
02368     selectButton->setEnabled( (listbox->count() > 0) );
02369     editButton->setEnabled( (listbox->count() > 0) );
02370 }
02371 
02372 void SmartPlaylistDialog::getSmartPlaylist(QString &category, QString &name)
02373 {
02374    category = categoryCombo->currentText();
02375    name = listbox->currentText();
02376 }
02377 
02378 #endif
02379 /*
02380 ---------------------------------------------------------------------
02381 */
02382 
02383 SmartPLDateDialog::SmartPLDateDialog(MythScreenStack *parent)
02384                  :MythScreenType(parent, "SmartPLDateDialog"),
02385                   m_updating(false), m_fixedRadio(NULL), m_daySpin(NULL),
02386                   m_monthSpin(NULL), m_yearSpin(NULL), m_nowRadio(NULL),
02387                   m_addDaysSpin(NULL), m_statusText(NULL),
02388                   m_cancelButton(NULL), m_okButton(NULL)
02389 {
02390     m_updating = false;
02391 }
02392 
02393 bool SmartPLDateDialog::Create(void)
02394 {
02395     if (!LoadWindowFromXML("music-ui.xml", "dateeditordialog", this))
02396         return false;
02397 
02398     bool err = false;
02399 
02400     UIUtilE::Assign(this, m_fixedRadio,   "fixeddatecheck", &err);
02401     UIUtilE::Assign(this, m_daySpin,      "dayspinbox",     &err);
02402     UIUtilE::Assign(this, m_monthSpin,    "monthspinbox",   &err);
02403     UIUtilE::Assign(this, m_yearSpin,     "yearspinbox",    &err);
02404     UIUtilE::Assign(this, m_nowRadio,     "nowcheck",       &err);
02405     UIUtilE::Assign(this, m_addDaysSpin,  "adddaysspinbox", &err);
02406     UIUtilE::Assign(this, m_statusText,   "statustext",     &err);
02407     UIUtilE::Assign(this, m_cancelButton, "cancelbutton",   &err);
02408     UIUtilE::Assign(this, m_okButton,     "okbutton",       &err);
02409 
02410     if (err)
02411     {
02412         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'dateeditordialog'");
02413         return false;
02414     }
02415 
02416     m_daySpin->SetRange(1, 31, 1);
02417     m_monthSpin->SetRange(1, 12, 1);
02418     m_yearSpin->SetRange(1900, 2099, 1);
02419     m_addDaysSpin->SetRange(-9999, 9999, 1);
02420 
02421 
02422     connect(m_fixedRadio, SIGNAL(toggled(bool)), this, SLOT(fixedCheckToggled(bool)));
02423     connect(m_nowRadio, SIGNAL(toggled(bool)), this, SLOT(nowCheckToggled(bool)));
02424     //connect(addDaysCheck, SIGNAL(toggled(bool)), this, SLOT(addDaysCheckToggled(bool)));
02425     connect(m_addDaysSpin, SIGNAL(itemSelected(MythUIButtonListItem*)),
02426             this, SLOT(valueChanged(void)));
02427     connect(m_daySpin, SIGNAL(itemSelected(MythUIButtonListItem*)),
02428             this, SLOT(valueChanged(void)));
02429     connect(m_monthSpin, SIGNAL(itemSelected(MythUIButtonListItem*)),
02430             this, SLOT(valueChanged(void)));
02431     connect(m_yearSpin, SIGNAL(itemSelected(MythUIButtonListItem*)),
02432             this, SLOT(valueChanged(void)));
02433 
02434     connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
02435     connect(m_okButton, SIGNAL(Clicked()), this, SLOT(okPressed()));
02436 
02437     valueChanged();
02438 
02439     BuildFocusList();
02440 
02441     return true;
02442 }
02443 
02444 SmartPLDateDialog::~SmartPLDateDialog(void)
02445 {
02446 }
02447 
02448 QString SmartPLDateDialog::getDate(void)
02449 {
02450     QString sResult;
02451 
02452     if (m_fixedRadio->GetBooleanCheckState())
02453     {
02454         QString day = m_daySpin->GetValue();
02455         if (m_daySpin->GetIntValue() < 10)
02456             day = "0" + day;
02457 
02458         QString month = m_monthSpin->GetValue();
02459         if (m_monthSpin->GetIntValue() < 10)
02460             month = "0" + month;
02461 
02462         sResult = m_yearSpin->GetValue() + "-" + month + "-" + day;
02463     }
02464     else
02465        sResult = m_statusText->GetText();
02466 
02467     return sResult;
02468 }
02469 
02470 void SmartPLDateDialog::setDate(QString date)
02471 {
02472     if (date.startsWith("$DATE"))
02473     {
02474         m_nowRadio->SetCheckState(true);
02475         m_fixedRadio->SetCheckState(false);
02476 
02477         if (date.length() > 9)
02478         {
02479             bool bNegative = false;
02480             if (date[6] == '-')
02481                 bNegative = true;
02482 
02483             if (date.endsWith(" days"))
02484                 date = date.left(date.length() - 5);
02485 
02486             int nDays = date.mid(8).toInt();
02487             if (bNegative)
02488                 nDays = -nDays;
02489 
02490             m_addDaysSpin->SetValue(nDays);
02491         }
02492         else
02493             m_addDaysSpin->SetValue(0);
02494 
02495         nowCheckToggled(true);
02496     }
02497     else
02498     {
02499         int nYear = date.mid(0, 4).toInt();
02500         int nMonth = date.mid(5, 2).toInt();
02501         int nDay = date.mid(8, 2).toInt();
02502 
02503         m_daySpin->SetValue(nDay);
02504         m_monthSpin->SetValue(nMonth);
02505         m_yearSpin->SetValue(nYear);
02506 
02507         fixedCheckToggled(true);
02508     }
02509 }
02510 
02511 void SmartPLDateDialog::fixedCheckToggled(bool on)
02512 {
02513     if (m_updating)
02514         return;
02515 
02516     m_updating = true;
02517     m_daySpin->SetEnabled(on);
02518     m_monthSpin->SetEnabled(on);
02519     m_yearSpin->SetEnabled(on);
02520 
02521     m_nowRadio->SetCheckState(!on);
02522     m_addDaysSpin->SetEnabled(!on);
02523 
02524     valueChanged();
02525 
02526     m_updating = false;
02527 }
02528 
02529 void SmartPLDateDialog::nowCheckToggled(bool on)
02530 {
02531     if (m_updating)
02532         return;
02533 
02534     m_updating = true;
02535 
02536     m_fixedRadio->SetCheckState(!on);
02537     m_daySpin->SetEnabled(!on);
02538     m_monthSpin->SetEnabled(!on);
02539     m_yearSpin->SetEnabled(!on);
02540 
02541     m_addDaysSpin->SetEnabled(on);
02542 
02543     valueChanged();
02544 
02545     m_updating = false;
02546 }
02547 
02548 void SmartPLDateDialog::okPressed(void )
02549 {
02550     QString date = getDate();
02551 
02552     emit dateChanged(date);
02553 
02554     Close();
02555 }
02556 
02557 void SmartPLDateDialog::valueChanged(void)
02558 {
02559     bool bValidDate = true;
02560 
02561     if (m_fixedRadio->GetBooleanCheckState())
02562     {
02563         QString day = m_daySpin->GetValue();
02564         if (m_daySpin->GetIntValue() < 10)
02565             day = "0" + day;
02566 
02567         QString month = m_monthSpin->GetValue();
02568         if (m_monthSpin->GetIntValue() < 10)
02569             month = "0" + month;
02570 
02571         QString sDate = m_yearSpin->GetValue() + "-" + month + "-" + day;
02572         QDate date = QDate::fromString(sDate, Qt::ISODate);
02573         if (date.isValid())
02574             m_statusText->SetText(date.toString("dddd, d MMMM yyyy"));
02575         else
02576         {
02577             bValidDate = false;
02578             m_statusText->SetText(tr("Invalid Date"));
02579         }
02580     }
02581     else if (m_nowRadio->GetBooleanCheckState())
02582     {
02583         QString days;
02584         if (m_addDaysSpin->GetIntValue() > 0)
02585             days = QString("$DATE + %1 days").arg(m_addDaysSpin->GetIntValue());
02586         else if (m_addDaysSpin->GetIntValue() == 0)
02587             days = QString("$DATE");
02588         else
02589             days = QString("$DATE - %1 days").arg(
02590                 m_addDaysSpin->GetValue().right(m_addDaysSpin->GetValue().length() - 1));
02591 
02592         m_statusText->SetText(days);
02593     }
02594 
02595     if (bValidDate)
02596         m_statusText->SetFontState("valid");
02597     else
02598         m_statusText->SetFontState("error");
02599 
02600     m_okButton->SetEnabled(bValidDate);
02601 }
02602 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends