00001
00002 #include <unistd.h>
00003 #include <iostream>
00004 using namespace std;
00005
00006
00007 #include <QSqlDriver>
00008 #include <QKeyEvent>
00009 #include <QSqlField>
00010
00011
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
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
00171 if (Field->type == ftBoolean)
00172 {
00173
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
00320 bool SmartPLCriteriaRow::saveToDatabase(int smartPlaylistID)
00321 {
00322
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
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
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
00607
00608
00609
00610
00611
00612
00613
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
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
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
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
00767 int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
00768
00769
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
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
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
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
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
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
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
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
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
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
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
01116 bool SmartPlaylistEditor::deleteSmartPlaylist(QString category, QString name)
01117 {
01118
01119 int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
01120
01121 MSqlQuery query(MSqlQuery::InitCon());
01122
01123
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
01139
01140 return true;
01141 }
01142 }
01143 else
01144 {
01145 MythDB::DBError("Delete smartplaylist", query);
01146 return false;
01147 }
01148
01149
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
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
01165
01166 bool SmartPlaylistEditor::deleteCategory(QString category)
01167 {
01168 int categoryid = SmartPlaylistEditor::lookupCategoryID(category);
01169 MSqlQuery query(MSqlQuery::InitCon());
01170
01171
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
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
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
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
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
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
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
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
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
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
01461 new MythUIButtonListItem(m_value2Selector, m_criteriaRow->Value2);
01462 m_value2Selector->SetValue(m_criteriaRow->Value2);
01463 }
01464 }
01465
01466
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
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
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
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
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
01563 if (fieldType != ftString && SmartPLOperators[x].stringOnly)
01564 continue;
01565
01566
01567 if (fieldType == ftBoolean && !SmartPLOperators[x].validForBoolean)
01568 continue;
01569
01570 new MythUIButtonListItem(m_operatorSelector, SmartPLOperators[x].name);
01571 }
01572
01573
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
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
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
02064
02065 vbox = new Q3VBoxLayout((QWidget *) 0, (int)(10 * hmult));
02066
02067 Q3HBoxLayout *hbox = new Q3HBoxLayout(vbox, (int)(10 * wmult));
02068
02069
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
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
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
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
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
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
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
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
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