00001
00002 #include <QCoreApplication>
00003
00004
00005 #include "mythprogressdialog.h"
00006 #include "mythuibuttonlist.h"
00007 #include "channelsettings.h"
00008 #include "transporteditor.h"
00009 #include "mythuicheckbox.h"
00010 #include "mythuitextedit.h"
00011 #include "channeleditor.h"
00012 #include "mythdialogbox.h"
00013 #include "mythuibutton.h"
00014 #include "channelutil.h"
00015 #include "importicons.h"
00016 #include "mythlogging.h"
00017 #include "mythuitext.h"
00018 #include "mythwizard.h"
00019 #include "scanwizard.h"
00020 #include "sourceutil.h"
00021 #include "cardutil.h"
00022 #include "settings.h"
00023 #include "mythdb.h"
00024
00025 ChannelWizard::ChannelWizard(int id, int default_sourceid)
00026 : ConfigurationWizard()
00027 {
00028 setLabel(QObject::tr("Channel Options"));
00029
00030
00031 addChild(cid = new ChannelID());
00032 cid->setValue(id);
00033
00034 ChannelOptionsCommon *common =
00035 new ChannelOptionsCommon(*cid, default_sourceid);
00036 addChild(common);
00037
00038 ChannelOptionsFilters *filters =
00039 new ChannelOptionsFilters(*cid);
00040 addChild(filters);
00041
00042 QStringList cardtypes = ChannelUtil::GetCardTypes(cid->getValue().toUInt());
00043 bool all_v4l = !cardtypes.empty();
00044 bool all_asi = !cardtypes.empty();
00045 for (uint i = 0; i < (uint) cardtypes.size(); i++)
00046 {
00047 all_v4l &= CardUtil::IsV4L(cardtypes[i]);
00048 all_asi &= cardtypes[i] == "ASI";
00049 }
00050
00051 if (all_v4l)
00052 addChild(new ChannelOptionsV4L(*cid));
00053 else if (all_asi)
00054 addChild(new ChannelOptionsRawTS(*cid));
00055 }
00056
00058
00059 ChannelEditor::ChannelEditor(MythScreenStack *parent)
00060 : MythScreenType(parent, "channeleditor"),
00061 m_sourceFilter(FILTER_ALL),
00062 m_currentSortMode(QObject::tr("Channel Name")),
00063 m_currentHideMode(false),
00064 m_channelList(NULL), m_sourceList(NULL), m_preview(NULL),
00065 m_channame(NULL), m_channum(NULL), m_callsign(NULL),
00066 m_chanid(NULL), m_sourcename(NULL), m_compoundname(NULL)
00067 {
00068 }
00069
00070 bool ChannelEditor::Create()
00071 {
00072 bool foundtheme = false;
00073
00074
00075 foundtheme = LoadWindowFromXML("config-ui.xml", "channeloverview", this);
00076
00077 if (!foundtheme)
00078 return false;
00079
00080 MythUIButtonList *sortList = dynamic_cast<MythUIButtonList *>(GetChild("sorting"));
00081 m_sourceList = dynamic_cast<MythUIButtonList *>(GetChild("source"));
00082 m_channelList = dynamic_cast<MythUIButtonList *>(GetChild("channels"));
00083 m_preview = dynamic_cast<MythUIImage *>(GetChild("preview"));
00084 m_channame = dynamic_cast<MythUIText *>(GetChild("name"));
00085 m_channum = dynamic_cast<MythUIText *>(GetChild("channum"));
00086 m_callsign = dynamic_cast<MythUIText *>(GetChild("callsign"));
00087 m_chanid = dynamic_cast<MythUIText *>(GetChild("chanid"));
00088 m_sourcename = dynamic_cast<MythUIText *>(GetChild("sourcename"));
00089 m_compoundname = dynamic_cast<MythUIText *>(GetChild("compoundname"));
00090
00091 MythUIButton *deleteButton = dynamic_cast<MythUIButton *>(GetChild("delete"));
00092 MythUIButton *scanButton = dynamic_cast<MythUIButton *>(GetChild("scan"));
00093 MythUIButton *importIconButton = dynamic_cast<MythUIButton *>(GetChild("importicons"));
00094 MythUIButton *transportEditorButton = dynamic_cast<MythUIButton *>(GetChild("edittransport"));
00095
00096 MythUICheckBox *hideCheck = dynamic_cast<MythUICheckBox *>(GetChild("nochannum"));
00097
00098 if (!sortList || !m_sourceList || !m_channelList || !deleteButton ||
00099 !scanButton || !importIconButton || !transportEditorButton ||
00100 !hideCheck)
00101 {
00102
00103 return false;
00104 }
00105
00106
00107 deleteButton->SetHelpText(tr("Delete all channels on currently selected source(s)."));
00108
00109
00110 new MythUIButtonListItem(sortList, tr("Channel Name"));
00111 new MythUIButtonListItem(sortList, tr("Channel Number"));
00112 connect(m_sourceList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00113 SLOT(setSourceID(MythUIButtonListItem *)));
00114 sortList->SetValue(m_currentSortMode);
00115
00116
00117
00118 new MythUIButtonListItem(m_sourceList,tr("All"),
00119 qVariantFromValue((int)FILTER_ALL));
00120 MSqlQuery query(MSqlQuery::InitCon());
00121 query.prepare("SELECT name, sourceid FROM videosource");
00122 if (query.exec())
00123 {
00124 while(query.next())
00125 {
00126 new MythUIButtonListItem(m_sourceList, query.value(0).toString(),
00127 query.value(1).toInt());
00128 }
00129 }
00130 new MythUIButtonListItem(m_sourceList,tr("(Unassigned)"),
00131 qVariantFromValue((int)FILTER_UNASSIGNED));
00132 connect(sortList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00133 SLOT(setSortMode(MythUIButtonListItem *)));
00134
00135
00136 hideCheck->SetCheckState(m_currentHideMode);
00137 connect(hideCheck, SIGNAL(toggled(bool)),
00138 SLOT(setHideMode(bool)));
00139
00140
00141 scanButton->SetHelpText(tr("Starts the channel scanner."));
00142 scanButton->SetEnabled(SourceUtil::IsAnySourceScanable());
00143
00144
00145 importIconButton->SetHelpText(tr("Starts the icon downloader"));
00146 importIconButton->SetEnabled(true);
00147 connect(importIconButton, SIGNAL(Clicked()), SLOT(channelIconImport()));
00148
00149
00150 transportEditorButton->SetHelpText(
00151 tr("Allows you to edit the transports directly. "
00152 "This is rarely required unless you are using "
00153 "a satellite dish and must enter an initial "
00154 "frequency to for the channel scanner to try."));
00155 connect(transportEditorButton, SIGNAL(Clicked()), SLOT(transportEditor()));
00156
00157
00158 connect(m_channelList, SIGNAL(itemClicked(MythUIButtonListItem *)),
00159 SLOT(edit(MythUIButtonListItem *)));
00160 connect(m_channelList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00161 SLOT(itemChanged(MythUIButtonListItem *)));
00162 connect(scanButton, SIGNAL(Clicked()), SLOT(scan()));
00163 connect(deleteButton, SIGNAL(Clicked()), SLOT(deleteChannels()));
00164
00165 fillList();
00166
00167 BuildFocusList();
00168
00169 return true;
00170 }
00171
00172 bool ChannelEditor::keyPressEvent(QKeyEvent *event)
00173 {
00174 if (GetFocusWidget()->keyPressEvent(event))
00175 return true;
00176
00177 bool handled = false;
00178 QStringList actions;
00179 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
00180
00181 for (int i = 0; i < actions.size() && !handled; i++)
00182 {
00183 QString action = actions[i];
00184 handled = true;
00185
00186 if (action == "MENU")
00187 menu();
00188 else if (action == "DELETE")
00189 del();
00190 else if (action == "EDIT")
00191 edit();
00192 else
00193 handled = false;
00194 }
00195
00196 if (!handled && MythScreenType::keyPressEvent(event))
00197 handled = true;
00198
00199 return handled;
00200 }
00201
00202 void ChannelEditor::itemChanged(MythUIButtonListItem *item)
00203 {
00204 if (!item)
00205 return;
00206
00207 if (m_preview)
00208 {
00209 m_preview->Reset();
00210 QString iconpath = item->GetImage();
00211 if (!iconpath.isEmpty())
00212 {
00213 m_preview->SetFilename(iconpath);
00214 m_preview->Load();
00215 }
00216 }
00217
00218 if (m_channame)
00219 m_channame->SetText(item->GetText("name"));
00220
00221 if (m_channum)
00222 m_channum->SetText(item->GetText("channum"));
00223
00224 if (m_callsign)
00225 m_callsign->SetText(item->GetText("callsign"));
00226
00227 if (m_chanid)
00228 m_chanid->SetText(item->GetText("chanid"));
00229
00230 if (m_sourcename)
00231 m_sourcename->SetText(item->GetText("sourcename"));
00232
00233 if (m_compoundname)
00234 m_compoundname->SetText(item->GetText("compoundname"));
00235 }
00236
00237 void ChannelEditor::fillList(void)
00238 {
00239 QString currentValue = m_channelList->GetValue();
00240 uint currentIndex = qMax(m_channelList->GetCurrentPos(), 0);
00241 m_channelList->Reset();
00242 QString newchanlabel = tr("(Add New Channel)");
00243 MythUIButtonListItem *item = new MythUIButtonListItem(m_channelList, "");
00244 item->SetText(newchanlabel, "compoundname");
00245 item->SetText(newchanlabel, "name");
00246
00247 bool fAllSources = true;
00248
00249 QString querystr = "SELECT channel.name,channum,chanid,callsign,icon,"
00250 "visible ,videosource.name FROM channel "
00251 "LEFT JOIN videosource ON "
00252 "(channel.sourceid = videosource.sourceid) ";
00253
00254 if (m_sourceFilter == FILTER_ALL)
00255 {
00256 fAllSources = true;
00257 }
00258 else
00259 {
00260 querystr += QString(" WHERE channel.sourceid='%1' ")
00261 .arg(m_sourceFilter);
00262 fAllSources = false;
00263 }
00264
00265 if (m_currentSortMode == tr("Channel Name"))
00266 {
00267 querystr += " ORDER BY channel.name";
00268 }
00269 else if (m_currentSortMode == tr("Channel Number"))
00270 {
00271 querystr += " ORDER BY channum + 0";
00272 }
00273
00274 MSqlQuery query(MSqlQuery::InitCon());
00275 query.prepare(querystr);
00276
00277 uint selidx = 0, idx = 1;
00278 if (query.exec() && query.size() > 0)
00279 {
00280 for (; query.next() ; idx++)
00281 {
00282 QString name = query.value(0).toString();
00283 QString channum = query.value(1).toString();
00284 QString chanid = query.value(2).toString();
00285 QString callsign = query.value(3).toString();
00286 QString icon = query.value(4).toString();
00287 bool visible = query.value(5).toBool();
00288 QString sourceid = "Unassigned";
00289
00290 QString state = "normal";
00291
00292 if (!visible)
00293 state = "disabled";
00294
00295 if (!query.value(6).toString().isEmpty())
00296 {
00297 sourceid = query.value(6).toString();
00298 if (fAllSources && m_sourceFilter == FILTER_UNASSIGNED)
00299 continue;
00300 }
00301 else
00302 state = "warning";
00303
00304 if (channum.isEmpty() && m_currentHideMode)
00305 continue;
00306
00307 if (name.isEmpty())
00308 name = "(Unnamed : " + chanid + ")";
00309
00310 QString compoundname = name;
00311
00312 if (m_currentSortMode == tr("Channel Name"))
00313 {
00314 if (!channum.isEmpty())
00315 compoundname += " (" + channum + ")";
00316 }
00317 else if (m_currentSortMode == tr("Channel Number"))
00318 {
00319 if (!channum.isEmpty())
00320 compoundname = channum + ". " + compoundname;
00321 else
00322 compoundname = "???. " + compoundname;
00323 }
00324
00325 if (m_sourceFilter == FILTER_ALL)
00326 compoundname += " (" + sourceid + ")";
00327
00328 bool sel = (chanid == currentValue);
00329 selidx = (sel) ? idx : selidx;
00330 item = new MythUIButtonListItem(m_channelList, "",
00331 qVariantFromValue(chanid));
00332 item->SetText(compoundname, "compoundname");
00333 item->SetText(name, "name");
00334 item->SetText(channum, "channum");
00335 item->SetText(chanid, "chanid");
00336 item->SetText(callsign, "callsign");
00337 item->SetText(sourceid, "sourcename");
00338 item->SetImage(icon);
00339 item->SetImage(icon, "icon");
00340 item->DisplayState(state, "status");
00341 }
00342 }
00343
00344
00345
00346 m_channelList->SetItemCurrent((!selidx && currentIndex < idx) ? currentIndex : selidx);
00347 }
00348
00349 void ChannelEditor::setSortMode(MythUIButtonListItem *item)
00350 {
00351 if (!item)
00352 return;
00353
00354 QString sortName = item->GetText();
00355
00356 if (m_currentSortMode != sortName)
00357 {
00358 m_currentSortMode = sortName;
00359 fillList();
00360 }
00361 }
00362
00363 void ChannelEditor::setSourceID(MythUIButtonListItem *item)
00364 {
00365 if (!item)
00366 return;
00367
00368 QString sourceName = item->GetText();
00369 int sourceID = item->GetData().toInt();
00370
00371 if (m_sourceFilter != sourceID)
00372 {
00373 m_sourceFilterName = sourceName;
00374 m_sourceFilter = sourceID;
00375 fillList();
00376 }
00377 }
00378
00379 void ChannelEditor::setHideMode(bool hide)
00380 {
00381 if (m_currentHideMode != hide)
00382 {
00383 m_currentHideMode = hide;
00384 fillList();
00385 }
00386 }
00387
00388 void ChannelEditor::del()
00389 {
00390 MythUIButtonListItem *item = m_channelList->GetItemCurrent();
00391
00392 if (!item)
00393 return;
00394
00395 QString message = tr("Delete channel '%1'?").arg(item->GetText("name"));
00396
00397 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00398 MythConfirmationDialog *dialog = new MythConfirmationDialog(popupStack, message, true);
00399
00400 if (dialog->Create())
00401 {
00402 dialog->SetData(qVariantFromValue(item));
00403 dialog->SetReturnEvent(this, "delsingle");
00404 popupStack->AddScreen(dialog);
00405 }
00406 else
00407 delete dialog;
00408
00409 }
00410
00411 void ChannelEditor::deleteChannels(void)
00412 {
00413 const QString currentLabel = m_sourceList->GetValue();
00414
00415 bool del_all = m_sourceFilter == FILTER_ALL;
00416 bool del_nul = m_sourceFilter == FILTER_UNASSIGNED;
00417
00418 QString message =
00419 (del_all) ? tr("Delete ALL channels?") :
00420 ((del_nul) ? tr("Delete all unassigned channels?") :
00421 tr("Delete all channels on %1?").arg(currentLabel));
00422
00423 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00424 MythConfirmationDialog *dialog = new MythConfirmationDialog(popupStack, message, true);
00425
00426 if (dialog->Create())
00427 {
00428 dialog->SetReturnEvent(this, "delall");
00429 popupStack->AddScreen(dialog);
00430 }
00431 else
00432 delete dialog;
00433 }
00434
00435 void ChannelEditor::edit(MythUIButtonListItem *item)
00436 {
00437 if (!item)
00438 item = m_channelList->GetItemCurrent();
00439
00440 if (!item)
00441 return;
00442
00443 int chanid = item->GetData().toInt();
00444 ChannelWizard cw(chanid, m_sourceFilter);
00445 cw.exec();
00446
00447 fillList();
00448 }
00449
00450 void ChannelEditor::menu()
00451 {
00452 MythUIButtonListItem *item = m_channelList->GetItemCurrent();
00453
00454 if (!item)
00455 return;
00456
00457 int chanid = item->GetData().toInt();
00458 if (chanid == 0)
00459 edit(item);
00460 else
00461 {
00462 QString label = tr("Channel Options");
00463
00464 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00465
00466 MythDialogBox *menu = new MythDialogBox(label, popupStack, "chanoptmenu");
00467
00468 if (menu->Create())
00469 {
00470 menu->SetReturnEvent(this, "channelopts");
00471
00472 menu->AddButton(tr("Edit"));
00473
00474
00475
00476
00477 menu->AddButton(tr("Delete"));
00478
00479 popupStack->AddScreen(menu);
00480 }
00481 else
00482 {
00483 delete menu;
00484 return;
00485 }
00486 }
00487 }
00488
00489 void ChannelEditor::scan(void)
00490 {
00491 #ifdef USING_BACKEND
00492 ScanWizard *scanwizard = new ScanWizard(m_sourceFilter);
00493 scanwizard->exec(false, true);
00494 scanwizard->deleteLater();
00495
00496 fillList();
00497 #else
00498 LOG(VB_GENERAL, LOG_ERR,
00499 "You must compile the backend to be able to scan for channels");
00500 #endif
00501 }
00502
00503 void ChannelEditor::transportEditor(void)
00504 {
00505 TransportListEditor *editor = new TransportListEditor(m_sourceFilter);
00506 editor->exec();
00507 editor->deleteLater();
00508
00509 fillList();
00510 }
00511
00512 void ChannelEditor::channelIconImport(void)
00513 {
00514 if (m_channelList->GetCount() == 0)
00515 {
00516 ShowOkPopup(tr("Add some channels first!"));
00517 return;
00518 }
00519
00520 int channelID = 0;
00521 MythUIButtonListItem *item = m_channelList->GetItemCurrent();
00522 if (item)
00523 channelID = item->GetData().toInt();
00524
00525
00526 QString querystr = QString("SELECT channel.name FROM channel "
00527 "WHERE chanid='%1'").arg(channelID);
00528 QString channelname;
00529 MSqlQuery query(MSqlQuery::InitCon());
00530 query.prepare(querystr);
00531
00532 if (query.exec() && query.next())
00533 {
00534 channelname = query.value(0).toString();
00535 }
00536
00537 QString label = tr("Icon Import Options");
00538
00539 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00540
00541 MythDialogBox *menu = new MythDialogBox(label, popupStack, "iconoptmenu");
00542
00543 if (menu->Create())
00544 {
00545 menu->SetReturnEvent(this, "iconimportopt");
00546
00547 menu->AddButton(tr("Download all icons..."));
00548 menu->AddButton(tr("Rescan for missing icons..."));
00549 if (!channelname.isEmpty())
00550 menu->AddButton(tr("Download icon for %1").arg(channelname),
00551 channelname);
00552
00553 popupStack->AddScreen(menu);
00554 }
00555 else
00556 {
00557 delete menu;
00558 return;
00559 }
00560 }
00561
00562 void ChannelEditor::customEvent(QEvent *event)
00563 {
00564 if (event->type() == DialogCompletionEvent::kEventType)
00565 {
00566 DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
00567
00568 QString resultid= dce->GetId();
00569 int buttonnum = dce->GetResult();
00570
00571 if (resultid == "channelopts")
00572 {
00573 switch (buttonnum)
00574 {
00575 case 0 :
00576 edit(m_channelList->GetItemCurrent());
00577 break;
00578 case 1 :
00579 del();
00580 break;
00581 }
00582 }
00583 else if (resultid == "delsingle" && buttonnum == 1)
00584 {
00585 MythUIButtonListItem *item =
00586 qVariantValue<MythUIButtonListItem *>(dce->GetData());
00587 if (!item)
00588 return;
00589 uint chanid = item->GetData().toUInt();
00590 if (chanid && ChannelUtil::DeleteChannel(chanid))
00591 m_channelList->RemoveItem(item);
00592 }
00593 else if (resultid == "delall" && buttonnum == 1)
00594 {
00595 bool del_all = m_sourceFilter == FILTER_ALL;
00596 bool del_nul = m_sourceFilter == FILTER_UNASSIGNED;
00597
00598 MSqlQuery query(MSqlQuery::InitCon());
00599 if (del_all)
00600 {
00601 query.prepare("TRUNCATE TABLE channel");
00602 }
00603 else if (del_nul)
00604 {
00605 query.prepare("SELECT sourceid "
00606 "FROM videosource "
00607 "GROUP BY sourceid");
00608
00609 if (!query.exec() || !query.isActive())
00610 {
00611 MythDB::DBError("ChannelEditor Delete Channels", query);
00612 return;
00613 }
00614
00615 QString tmp = "";
00616 while (query.next())
00617 tmp += "'" + query.value(0).toString() + "',";
00618
00619 if (tmp.isEmpty())
00620 {
00621 query.prepare("TRUNCATE TABLE channel");
00622 }
00623 else
00624 {
00625 tmp = tmp.left(tmp.length() - 1);
00626 query.prepare(QString("DELETE FROM channel "
00627 "WHERE sourceid NOT IN (%1)").arg(tmp));
00628 }
00629 }
00630 else
00631 {
00632 query.prepare("DELETE FROM channel "
00633 "WHERE sourceid = :SOURCEID");
00634 query.bindValue(":SOURCEID", m_sourceFilter);
00635 }
00636
00637 if (!query.exec())
00638 MythDB::DBError("ChannelEditor Delete Channels", query);
00639
00640 fillList();
00641 }
00642 else if (resultid == "iconimportopt")
00643 {
00644 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00645
00646 ImportIconsWizard *iconwizard;
00647
00648 QString channelname = dce->GetData().toString();
00649
00650 switch (buttonnum)
00651 {
00652 case 0 :
00653 iconwizard = new ImportIconsWizard(mainStack, false);
00654 break;
00655 case 1 :
00656 iconwizard = new ImportIconsWizard(mainStack, true);
00657 break;
00658 case 2 :
00659 iconwizard = new ImportIconsWizard(mainStack, true,
00660 channelname);
00661 break;
00662 default:
00663 return;
00664 }
00665
00666 if (iconwizard->Create())
00667 {
00668 connect(iconwizard, SIGNAL(Exiting()), SLOT(fillList()));
00669 mainStack->AddScreen(iconwizard);
00670 }
00671 else
00672 delete iconwizard;
00673 }
00674 }
00675 }