MythTV  0.26-pre
channeleditor.cpp
Go to the documentation of this file.
00001 // Qt
00002 #include <QCoreApplication>
00003 
00004 // MythTV
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     // Must be first.
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     // Load the theme for this screen
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     // Delete button help text
00107     deleteButton->SetHelpText(tr("Delete all channels on currently selected source(s)."));
00108 
00109     // Sort List
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     // Source List
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     // Hide/Show channels without channum checkbox
00136     hideCheck->SetCheckState(m_currentHideMode);
00137     connect(hideCheck, SIGNAL(toggled(bool)),
00138             SLOT(setHideMode(bool)));
00139 
00140     // Scan Button
00141     scanButton->SetHelpText(tr("Starts the channel scanner."));
00142     scanButton->SetEnabled(SourceUtil::IsAnySourceScanable());
00143 
00144     // Import Icons Button
00145     importIconButton->SetHelpText(tr("Starts the icon downloader"));
00146     importIconButton->SetEnabled(true);
00147     connect(importIconButton,  SIGNAL(Clicked()), SLOT(channelIconImport()));
00148 
00149     // Transport Editor Button
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     // Other signals
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     // Make sure we select the current item, or the following one after
00345     // deletion, with wrap around to "(New Channel)" after deleting last item.
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 //             if ()
00474 //                 menu->AddButton(tr("Set Hidden"));
00475 //             else
00476 //                 menu->AddButton(tr("Set Visible"));
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     // Get selected channel name from database
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 : // Import all icons
00653                     iconwizard = new ImportIconsWizard(mainStack, false);
00654                     break;
00655                 case 1 : // Rescan for missing
00656                     iconwizard = new ImportIconsWizard(mainStack, true);
00657                     break;
00658                 case 2 : // Import a single channel icon
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends