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