00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <QTextStream>
00010 #include <iostream>
00011
00012 using namespace std;
00013
00014
00015 #include "channelimporter.h"
00016 #include "mythdialogs.h"
00017 #include "mythwidgets.h"
00018 #include "mythdb.h"
00019 #include "mpegstreamdata.h"
00020 #include "channelutil.h"
00021
00022 #define LOC QString("ChanImport: ")
00023
00024 static QString map_str(QString str)
00025 {
00026 if (str.isEmpty())
00027 return "";
00028 str.detach();
00029 return str;
00030 }
00031
00032 void ChannelImporter::Process(const ScanDTVTransportList &_transports)
00033 {
00034 if (_transports.empty())
00035 {
00036 if (use_gui)
00037 {
00038 LOG(VB_GENERAL, LOG_INFO, LOC + (ChannelUtil::GetChannelCount() ?
00039 "No new channels to process" :
00040 "No channels to process.."));
00041 MythPopupBox::showOkPopup(
00042 GetMythMainWindow(), QObject::tr("Channel Importer"),
00043 ChannelUtil::GetChannelCount()
00044 ? QObject::tr("Failed to find any new channels!")
00045 : QObject::tr("Failed to find any channels."));
00046 }
00047 else
00048 {
00049 cout << (ChannelUtil::GetChannelCount() ?
00050 "No new channels to process" :
00051 "No channels to process..");
00052 }
00053
00054 return;
00055 }
00056
00057 ScanDTVTransportList transports = _transports;
00058
00059
00060 if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_ANY))
00061 {
00062 cout << "Before processing: " << endl;
00063 ChannelImporterBasicStats infoA = CollectStats(transports);
00064 cout << FormatChannels(transports, infoA).toAscii().constData() << endl;
00065 cout << endl << endl;
00066 }
00067
00068 uint saved_scan = 0;
00069 if (do_save)
00070 saved_scan = SaveScan(transports);
00071
00072 CleanupDuplicates(transports);
00073
00074 FilterServices(transports);
00075
00076
00077 uint sourceid = transports[0].channels[0].source_id;
00078 ScanDTVTransportList db_trans = GetDBTransports(sourceid, transports);
00079
00080
00081 FixUpOpenCable(transports);
00082
00083
00084 uint deleted_count = 0;
00085 if (do_delete)
00086 {
00087 ScanDTVTransportList trans = transports;
00088 for (uint i = 0; i < db_trans.size(); i++)
00089 trans.push_back(db_trans[i]);
00090 deleted_count = DeleteChannels(trans);
00091 if (deleted_count)
00092 transports = trans;
00093 }
00094
00095
00096 ChannelImporterBasicStats info = CollectStats(transports);
00097
00098
00099 ChannelImporterUniquenessStats stats =
00100 CollectUniquenessStats(transports, info);
00101
00102
00103 cout << FormatChannels(transports, info).toAscii().constData() << endl;
00104
00105
00106 QString msg = GetSummary(transports.size(), info, stats);
00107 cout << msg.toAscii().constData() << endl << endl;
00108
00109 if (do_insert)
00110 InsertChannels(transports, info);
00111
00112 if (do_delete && sourceid)
00113 DeleteUnusedTransports(sourceid);
00114
00115 if (do_delete || do_insert)
00116 ScanInfo::MarkProcessed(saved_scan);
00117 }
00118
00119 QString ChannelImporter::toString(ChannelType type)
00120 {
00121 switch (type)
00122 {
00123
00124 case kATSCNonConflicting: return "ATSC";
00125 case kDVBNonConflicting: return "DVB";
00126 case kSCTENonConflicting: return "SCTE";
00127 case kMPEGNonConflicting: return "MPEG";
00128 case kNTSCNonConflicting: return "NTSC";
00129
00130 case kATSCConflicting: return "ATSC";
00131 case kDVBConflicting: return "DVB";
00132 case kSCTEConflicting: return "SCTE";
00133 case kMPEGConflicting: return "MPEG";
00134 case kNTSCConflicting: return "NTSC";
00135 }
00136 return "Unknown";
00137 }
00138
00139 uint ChannelImporter::DeleteChannels(
00140 ScanDTVTransportList &transports)
00141 {
00142 vector<uint> off_air_list;
00143 QMap<uint,bool> deleted;
00144
00145 for (uint i = 0; i < transports.size(); i++)
00146 {
00147 for (uint j = 0; j < transports[i].channels.size(); j++)
00148 {
00149 ChannelInsertInfo chan = transports[i].channels[j];
00150 bool was_in_db = chan.db_mplexid && chan.channel_id;
00151 if (!was_in_db)
00152 continue;
00153
00154 if (!chan.in_pmt)
00155 off_air_list.push_back(i<<16|j);
00156 }
00157 }
00158
00159 ScanDTVTransportList newlist;
00160 if (off_air_list.empty())
00161 {
00162 return 0;
00163 }
00164
00165
00166
00167 QString msg = QObject::tr(
00168 "Found %n off-air channel(s).", "", off_air_list.size());
00169 DeleteAction action = QueryUserDelete(msg);
00170 if (kDeleteIgnoreAll == action)
00171 return 0;
00172
00173 if (kDeleteAll == action)
00174 {
00175 for (uint k = 0; k < off_air_list.size(); k++)
00176 {
00177 int i = off_air_list[k] >> 16, j = off_air_list[k] & 0xFFFF;
00178 ChannelUtil::DeleteChannel(
00179 transports[i].channels[j].channel_id);
00180 deleted[off_air_list[k]] = true;
00181 }
00182 }
00183 else if (kDeleteInvisibleAll == action)
00184 {
00185 for (uint k = 0; k < off_air_list.size(); k++)
00186 {
00187 int i = off_air_list[k] >> 16, j = off_air_list[k] & 0xFFFF;
00188 int chanid = transports[i].channels[j].channel_id;
00189 QString channum = ChannelUtil::GetChanNum(chanid);
00190 ChannelUtil::SetVisible(chanid, false);
00191 ChannelUtil::SetChannelValue("channum", QString("_%1").arg(channum),
00192 chanid);
00193 }
00194 }
00195 else
00196 {
00197
00198 }
00199
00200
00201
00202 if (deleted.size() == 0)
00203 return 0;
00204
00205
00206 for (uint i = 0; i < transports.size(); i++)
00207 {
00208 newlist.push_back(transports[i]);
00209 newlist.back().channels.clear();
00210 for (uint j = 0; j < transports[i].channels.size(); j++)
00211 {
00212 if (!deleted.contains(i<<16|j))
00213 {
00214 newlist.back().channels.push_back(
00215 transports[i].channels[j]);
00216 }
00217 }
00218 }
00219
00220
00221
00222 transports = newlist;
00223 return deleted.size();
00224 }
00225
00226 uint ChannelImporter::DeleteUnusedTransports(uint sourceid)
00227 {
00228 MSqlQuery query(MSqlQuery::InitCon());
00229 query.prepare(
00230 "SELECT mplexid FROM dtv_multiplex "
00231 "WHERE sourceid = :SOURCEID1 AND "
00232 " mplexid NOT IN "
00233 " (SELECT mplexid "
00234 " FROM channel "
00235 " WHERE sourceid = :SOURCEID2)");
00236 query.bindValue(":SOURCEID1", sourceid);
00237 query.bindValue(":SOURCEID2", sourceid);
00238 if (!query.exec())
00239 {
00240 MythDB::DBError("DeleteUnusedTransports() -- select", query);
00241 return 0;
00242 }
00243
00244 QString msg = QObject::tr("Found %n unused transport(s).", "", query.size());
00245
00246 LOG(VB_GENERAL, LOG_INFO, LOC + msg);
00247
00248 if (query.size() == 0)
00249 return 0;
00250
00251 DeleteAction action = QueryUserDelete(msg);
00252 if (kDeleteIgnoreAll == action)
00253 return 0;
00254
00255 if (kDeleteAll == action)
00256 {
00257 query.prepare(
00258 "DELETE FROM dtv_multiplex "
00259 "WHERE sourceid = :SOURCEID1 AND "
00260 " mplexid NOT IN "
00261 " (SELECT mplexid "
00262 " FROM channel "
00263 " WHERE sourceid = :SOURCEID2)");
00264 query.bindValue(":SOURCEID1", sourceid);
00265 query.bindValue(":SOURCEID2", sourceid);
00266 if (!query.exec())
00267 {
00268 MythDB::DBError("DeleteUnusedTransports() -- delete", query);
00269 return 0;
00270 }
00271 }
00272 else
00273 {
00274
00275 }
00276 return 0;
00277 }
00278
00279 void ChannelImporter::InsertChannels(
00280 const ScanDTVTransportList &transports,
00281 const ChannelImporterBasicStats &info)
00282 {
00283 ScanDTVTransportList list = transports;
00284 ScanDTVTransportList filtered;
00285
00286
00287
00288
00289 uint chantype = (uint) kChannelTypeNonConflictingFirst;
00290 for (; chantype <= (uint) kChannelTypeNonConflictingLast; chantype++)
00291 {
00292 ChannelType type = (ChannelType) chantype;
00293 uint new_chan, old_chan;
00294 CountChannels(list, info, type, new_chan, old_chan);
00295
00296 if (kNTSCNonConflicting == type)
00297 continue;
00298
00299 if (old_chan)
00300 {
00301 QString msg = QObject::tr("Found %n old %1 channel(s).", "", old_chan)
00302 .arg(toString(type));
00303
00304 UpdateAction action = QueryUserUpdate(msg);
00305 list = UpdateChannels(list, info, action, type, filtered);
00306 }
00307 if (new_chan)
00308 {
00309 QString msg = QObject::tr(
00310 "Found %n new non-conflicting %1 channel(s).", "", new_chan)
00311 .arg(toString(type));
00312
00313 InsertAction action = QueryUserInsert(msg);
00314 list = InsertChannels(list, info, action, type, filtered);
00315 }
00316 }
00317
00318 if (!is_interactive)
00319 return;
00320
00321
00322 ChannelImporterBasicStats ninfo = CollectStats(list);
00323 ChannelImporterUniquenessStats nstats = CollectUniquenessStats(list, ninfo);
00324 cout << endl << endl << "Printing remaining channels" << endl;
00325 cout << FormatChannels(list, ninfo).toAscii().constData() << endl;
00326 cout << GetSummary(list.size(), ninfo, nstats).toAscii().constData()
00327 << endl << endl;
00328
00329
00330
00331
00332
00333
00334
00335 chantype = (uint) kChannelTypeConflictingFirst;
00336 for (; chantype <= (uint) kChannelTypeConflictingLast; chantype++)
00337 {
00338
00339 ChannelType type = (ChannelType) chantype;
00340 uint new_chan, old_chan;
00341 CountChannels(list, info, type, new_chan, old_chan);
00342 if (new_chan)
00343 {
00344 QString msg = QObject::tr(
00345 "Found %n new conflicting %1 channel(s).", "", new_chan)
00346 .arg(toString(type));
00347
00348 InsertAction action = QueryUserInsert(msg);
00349 list = InsertChannels(list, info, action, type, filtered);
00350 }
00351 if (old_chan)
00352 {
00353 QString msg = QObject::tr("Found %n conflicting old %1 channel(s).",
00354 "", old_chan).arg(toString(type));
00355
00356 UpdateAction action = QueryUserUpdate(msg);
00357 list = UpdateChannels(list, info, action, type, filtered);
00358 }
00359 }
00360
00361
00362
00363
00364 }
00365
00366 ScanDTVTransportList ChannelImporter::InsertChannels(
00367 const ScanDTVTransportList &transports,
00368 const ChannelImporterBasicStats &info,
00369 InsertAction action, ChannelType type,
00370 ScanDTVTransportList &filtered)
00371 {
00372 QString channelFormat = "%1_%2";
00373
00374 ScanDTVTransportList next_list;
00375
00376 bool ignore_rest = false;
00377
00378
00379
00380 for (uint i = 0; i < transports.size(); i++)
00381 {
00382 bool created_new_transport = false;
00383 ScanDTVTransport new_transport;
00384 bool created_filter_transport = false;
00385 ScanDTVTransport filter_transport;
00386
00387 for (uint j = 0; j < transports[i].channels.size(); j++)
00388 {
00389 ChannelInsertInfo chan = transports[i].channels[j];
00390
00391 bool filter = false, handle = false;
00392 if (!chan.channel_id && (kInsertIgnoreAll == action) &&
00393 IsType(info, chan, type))
00394 {
00395 filter = true;
00396 }
00397 else if (!chan.channel_id && IsType(info, chan, type))
00398 {
00399 handle = true;
00400 }
00401
00402 if (ignore_rest)
00403 {
00404 cout<<QString("Skipping Insert: %1")
00405 .arg(FormatChannel(transports[i], chan))
00406 .toAscii().constData()<<endl;
00407 handle = false;
00408 }
00409
00410 if (handle && kInsertManual == action)
00411 {
00412 OkCancelType rc = QueryUserInsert(info, transports[i], chan);
00413 if (kOCTCancelAll == rc)
00414 {
00415 ignore_rest = true;
00416 handle = false;
00417 }
00418 else if (kOCTCancel == rc)
00419 {
00420 handle = false;
00421 }
00422 }
00423
00424 if (handle)
00425 {
00426 bool conflicting = false;
00427
00428 if (chan.chan_num.isEmpty() ||
00429 ChannelUtil::IsConflicting(chan.chan_num, chan.source_id))
00430 {
00431 if ((kATSCNonConflicting == type) ||
00432 (kATSCConflicting == type))
00433 {
00434 chan.chan_num = channelFormat
00435 .arg(chan.atsc_major_channel)
00436 .arg(chan.atsc_minor_channel);
00437 }
00438 else if (chan.si_standard == "dvb")
00439 {
00440 chan.chan_num = QString("%1")
00441 .arg(chan.service_id);
00442 }
00443 else
00444 {
00445 chan.chan_num = QString("%1-%2")
00446 .arg(chan.freqid)
00447 .arg(chan.service_id);
00448 }
00449
00450 conflicting = ChannelUtil::IsConflicting(
00451 chan.chan_num, chan.source_id);
00452 }
00453
00454 if (is_interactive &&
00455 (conflicting || (kChannelTypeConflictingFirst <= type)))
00456 {
00457 OkCancelType rc =
00458 QueryUserResolve(info, transports[i], chan);
00459
00460 conflicting = true;
00461 if (kOCTCancelAll == rc)
00462 ignore_rest = true;
00463 else if (kOCTOk == rc)
00464 conflicting = false;
00465 }
00466
00467 if (conflicting)
00468 {
00469 cout<<QString("Skipping Insert: %1")
00470 .arg(FormatChannel(transports[i], chan))
00471 .toAscii().constData()<<endl;
00472 handle = false;
00473 }
00474 }
00475
00476 bool inserted = false;
00477 if (handle)
00478 {
00479 int chanid = ChannelUtil::CreateChanID(
00480 chan.source_id, chan.chan_num);
00481
00482 chan.channel_id = (chanid > 0) ? chanid : chan.channel_id;
00483
00484 if (chan.channel_id && !chan.db_mplexid)
00485 {
00486 uint tsid = chan.vct_tsid;
00487 tsid = (tsid) ? tsid : chan.sdt_tsid;
00488 tsid = (tsid) ? tsid : chan.pat_tsid;
00489 tsid = (tsid) ? tsid : chan.vct_chan_tsid;
00490
00491 chan.db_mplexid = ChannelUtil::CreateMultiplex(
00492 chan.source_id, transports[i], tsid, chan.orig_netid);
00493 }
00494
00495 if (chan.channel_id && chan.db_mplexid)
00496 {
00497 chan.channel_id = chanid;
00498
00499 cout<<"Insert("<<chan.si_standard.toAscii().constData()
00500 <<"): "<<chan.chan_num.toAscii().constData()<<endl;
00501
00502 inserted = ChannelUtil::CreateChannel(
00503 chan.db_mplexid,
00504 chan.source_id,
00505 chan.channel_id,
00506 chan.callsign,
00507 chan.service_name,
00508 chan.chan_num,
00509 chan.service_id,
00510 chan.atsc_major_channel,
00511 chan.atsc_minor_channel,
00512 chan.use_on_air_guide,
00513 chan.hidden, chan.hidden_in_guide,
00514 chan.freqid,
00515 QString::null,
00516 QString::null,
00517 QString::null,
00518 chan.default_authority);
00519 }
00520 }
00521
00522 if (filter)
00523 {
00524 if (!created_filter_transport)
00525 {
00526 filter_transport = transports[i];
00527 filter_transport.channels.clear();
00528 created_filter_transport = true;
00529 }
00530 filter_transport.channels.push_back(transports[i].channels[j]);
00531 }
00532 else if (!inserted)
00533 {
00534 if (!created_new_transport)
00535 {
00536 new_transport = transports[i];
00537 new_transport.channels.clear();
00538 created_new_transport = true;
00539 }
00540 new_transport.channels.push_back(transports[i].channels[j]);
00541 }
00542 }
00543
00544 if (created_filter_transport)
00545 filtered.push_back(filter_transport);
00546
00547 if (created_new_transport)
00548 next_list.push_back(new_transport);
00549 }
00550
00551 return next_list;
00552 }
00553
00554 ScanDTVTransportList ChannelImporter::UpdateChannels(
00555 const ScanDTVTransportList &transports,
00556 const ChannelImporterBasicStats &info,
00557 UpdateAction action, ChannelType type,
00558 ScanDTVTransportList &filtered)
00559 {
00560 QString channelFormat = "%1_%2";
00561 bool renameChannels = false;
00562
00563 ScanDTVTransportList next_list;
00564
00565
00566
00567 for (uint i = 0; i < transports.size(); i++)
00568 {
00569 bool created_transport = false;
00570 ScanDTVTransport new_transport;
00571 bool created_filter_transport = false;
00572 ScanDTVTransport filter_transport;
00573
00574 for (uint j = 0; j < transports[i].channels.size(); j++)
00575 {
00576 ChannelInsertInfo chan = transports[i].channels[j];
00577
00578 bool filter = false, handle = false;
00579 if (chan.channel_id && (kUpdateIgnoreAll == action) &&
00580 IsType(info, chan, type))
00581 {
00582 filter = true;
00583 }
00584 else if (chan.channel_id && IsType(info, chan, type))
00585 {
00586 handle = true;
00587 }
00588
00589 if (handle)
00590 {
00591 bool conflicting = false;
00592
00593 if (chan.chan_num.isEmpty() || renameChannels ||
00594 ChannelUtil::IsConflicting(
00595 chan.chan_num, chan.source_id, chan.channel_id))
00596 {
00597 if (kATSCNonConflicting == type)
00598 {
00599 chan.chan_num = channelFormat
00600 .arg(chan.atsc_major_channel)
00601 .arg(chan.atsc_minor_channel);
00602 }
00603 else if (chan.si_standard == "dvb")
00604 {
00605 chan.chan_num = QString("%1")
00606 .arg(chan.service_id);
00607 }
00608 else
00609 {
00610 chan.chan_num = QString("%1-%2")
00611 .arg(chan.freqid)
00612 .arg(chan.service_id);
00613 }
00614
00615 conflicting = ChannelUtil::IsConflicting(
00616 chan.chan_num, chan.source_id, chan.channel_id);
00617 }
00618
00619 if (conflicting)
00620 {
00621 cout<<"Skipping Update("
00622 <<chan.si_standard.toAscii().constData()<<"): "
00623 <<chan.chan_num.toAscii().constData()<<endl;
00624 handle = false;
00625 }
00626 }
00627
00628 if (is_interactive && (kUpdateManual == action))
00629 {
00630
00631 }
00632
00633 bool updated = false;
00634 if (handle)
00635 {
00636 cout<<"Update("<<chan.si_standard.toAscii().constData()<<"): "
00637 <<chan.chan_num.toAscii().constData()<<endl;
00638
00639 ChannelUtil::UpdateInsertInfoFromDB(chan);
00640
00641 updated = ChannelUtil::UpdateChannel(
00642 chan.db_mplexid,
00643 chan.source_id,
00644 chan.channel_id,
00645 chan.callsign,
00646 chan.service_name,
00647 chan.chan_num,
00648 chan.service_id,
00649 chan.atsc_major_channel,
00650 chan.atsc_minor_channel,
00651 chan.use_on_air_guide,
00652 chan.hidden, chan.hidden_in_guide,
00653 chan.freqid,
00654 QString::null,
00655 QString::null,
00656 QString::null,
00657 chan.default_authority);
00658 }
00659
00660 if (filter)
00661 {
00662 if (!created_filter_transport)
00663 {
00664 filter_transport = transports[i];
00665 filter_transport.channels.clear();
00666 created_filter_transport = true;
00667 }
00668 filter_transport.channels.push_back(transports[i].channels[j]);
00669 }
00670 else if (!updated)
00671 {
00672 if (!created_transport)
00673 {
00674 new_transport = transports[i];
00675 new_transport.channels.clear();
00676 created_transport = true;
00677 }
00678 new_transport.channels.push_back(transports[i].channels[j]);
00679 }
00680 }
00681
00682 if (created_filter_transport)
00683 filtered.push_back(filter_transport);
00684
00685 if (created_transport)
00686 next_list.push_back(new_transport);
00687 }
00688
00689 return next_list;
00690 }
00691
00692 void ChannelImporter::CleanupDuplicates(ScanDTVTransportList &transports) const
00693 {
00694 ScanDTVTransportList no_dups;
00695
00696 DTVTunerType tuner_type = DTVTunerType::kTunerTypeATSC;
00697 if (!transports.empty())
00698 tuner_type = transports[0].tuner_type;
00699
00700 bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
00701 (DTVTunerType::kTunerTypeDVBS2 == tuner_type));
00702
00703 uint freq_mult = (is_dvbs) ? 1 : 1000;
00704
00705 vector<bool> ignore;
00706 ignore.resize(transports.size());
00707 for (uint i = 0; i < transports.size(); i++)
00708 {
00709 if (ignore[i])
00710 continue;
00711
00712 for (uint j = i+1; j < transports.size(); j++)
00713 {
00714 if (!transports[i].IsEqual(
00715 tuner_type, transports[j], 500 * freq_mult))
00716 {
00717 continue;
00718 }
00719
00720 for (uint k = 0; k < transports[j].channels.size(); k++)
00721 {
00722 bool found_same = false;
00723 for (uint l = 0; l < transports[i].channels.size(); l++)
00724 {
00725 if (transports[j].channels[k].IsSameChannel(
00726 transports[i].channels[l]))
00727 {
00728 found_same = true;
00729 transports[i].channels[l].ImportExtraInfo(
00730 transports[j].channels[k]);
00731 }
00732 }
00733 if (!found_same)
00734 transports[i].channels.push_back(transports[j].channels[k]);
00735 }
00736 ignore[j] = true;
00737 }
00738 no_dups.push_back(transports[i]);
00739 }
00740
00741 transports = no_dups;
00742 }
00743
00744 void ChannelImporter::FilterServices(ScanDTVTransportList &transports) const
00745 {
00746 bool require_av = (m_service_requirements & kRequireAV) == kRequireAV;
00747 bool require_a = m_service_requirements & kRequireAudio;
00748
00749 for (uint i = 0; i < transports.size(); i++)
00750 {
00751 ChannelInsertInfoList filtered;
00752 for (uint k = 0; k < transports[i].channels.size(); k++)
00753 {
00754 if (m_fta_only && transports[i].channels[k].is_encrypted &&
00755 transports[i].channels[k].decryption_status != kEncDecrypted)
00756 continue;
00757
00758 if (require_a && transports[i].channels[k].is_data_service)
00759 continue;
00760
00761 if (require_av && transports[i].channels[k].is_audio_service)
00762 continue;
00763
00764
00765 if (transports[i].channels[k].in_channels_conf &&
00766 !(transports[i].channels[k].in_pat ||
00767 transports[i].channels[k].in_pmt ||
00768 transports[i].channels[k].in_vct ||
00769 transports[i].channels[k].in_nit ||
00770 transports[i].channels[k].in_sdt))
00771 continue;
00772
00773 filtered.push_back(transports[i].channels[k]);
00774 }
00775 transports[i].channels = filtered;
00776 }
00777 }
00778
00783 ScanDTVTransportList ChannelImporter::GetDBTransports(
00784 uint sourceid, ScanDTVTransportList &transports) const
00785 {
00786 ScanDTVTransportList not_in_scan;
00787
00788 DTVTunerType tuner_type = DTVTunerType::kTunerTypeATSC;
00789 if (!transports.empty())
00790 tuner_type = transports[0].tuner_type;
00791
00792 bool is_dvbs =
00793 (DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
00794 (DTVTunerType::kTunerTypeDVBS2 == tuner_type);
00795
00796 uint freq_mult = (is_dvbs) ? 1 : 1000;
00797
00798 MSqlQuery query(MSqlQuery::InitCon());
00799 query.prepare(
00800 "SELECT mplexid "
00801 "FROM dtv_multiplex "
00802 "WHERE sourceid = :SOURCEID "
00803 "GROUP BY mplexid "
00804 "ORDER BY mplexid");
00805 query.bindValue(":SOURCEID", sourceid);
00806
00807 if (!query.exec())
00808 {
00809 MythDB::DBError("GetDBTransports()", query);
00810 return not_in_scan;
00811 }
00812
00813 while (query.next())
00814 {
00815 uint mplexid = query.value(0).toUInt();
00816
00817 ScanDTVTransport newt;
00818 if (!newt.FillFromDB(tuner_type, mplexid))
00819 continue;
00820
00821 bool newt_found = false;
00822 QMap<uint,bool> found_chan;
00823
00824 for (uint i = 0; i < transports.size(); i++)
00825 {
00826 if (!transports[i].IsEqual(tuner_type, newt, 500 * freq_mult, true))
00827 continue;
00828
00829 transports[i].mplex = mplexid;
00830 newt_found = true;
00831 for (uint j = 0; j < transports[i].channels.size(); j++)
00832 {
00833 ChannelInsertInfo &chan = transports[i].channels[j];
00834 for (uint k = 0; k < newt.channels.size(); k++)
00835 {
00836 if (newt.channels[k].IsSameChannel(chan))
00837 {
00838 found_chan[k] = true;
00839 chan.db_mplexid = mplexid;
00840 chan.channel_id = newt.channels[k].channel_id;
00841 }
00842 }
00843 }
00844 break;
00845 }
00846
00847 if (!newt_found)
00848 {
00849
00850
00851
00852
00853
00854
00855 }
00856 else
00857 {
00858 ScanDTVTransport tmp = newt;
00859 tmp.channels.clear();
00860
00861 for (uint k = 0; k < newt.channels.size(); k++)
00862 {
00863 if (!found_chan[k])
00864 tmp.channels.push_back(newt.channels[k]);
00865 }
00866
00867 if (tmp.channels.size())
00868 not_in_scan.push_back(tmp);
00869 }
00870 }
00871
00872 return not_in_scan;
00873 }
00874
00875 void ChannelImporter::FixUpOpenCable(ScanDTVTransportList &transports)
00876 {
00877 ChannelImporterBasicStats info;
00878 for (uint i = 0; i < transports.size(); i++)
00879 {
00880 for (uint j = 0; j < transports[i].channels.size(); j++)
00881 {
00882 ChannelInsertInfo &chan = transports[i].channels[j];
00883 if (((chan.could_be_opencable && (chan.si_standard == "mpeg")) ||
00884 chan.is_opencable) && !chan.in_vct)
00885 {
00886 chan.si_standard = "opencable";
00887 }
00888 }
00889 }
00890 }
00891
00892 ChannelImporterBasicStats ChannelImporter::CollectStats(
00893 const ScanDTVTransportList &transports)
00894 {
00895 ChannelImporterBasicStats info;
00896 for (uint i = 0; i < transports.size(); i++)
00897 {
00898 for (uint j = 0; j < transports[i].channels.size(); j++)
00899 {
00900 const ChannelInsertInfo &chan = transports[i].channels[j];
00901 int enc = (chan.is_encrypted) ?
00902 ((chan.decryption_status == kEncDecrypted) ? 2 : 1) : 0;
00903 info.atsc_channels[enc] += (chan.si_standard == "atsc");
00904 info.dvb_channels [enc] += (chan.si_standard == "dvb");
00905 info.mpeg_channels[enc] += (chan.si_standard == "mpeg");
00906 info.scte_channels[enc] += (chan.si_standard == "opencable");
00907 info.ntsc_channels[enc] += (chan.si_standard == "ntsc");
00908 if (chan.si_standard != "ntsc")
00909 {
00910 info.prognum_cnt[chan.service_id]++;
00911 info.channum_cnt[map_str(chan.chan_num)]++;
00912 }
00913 if (chan.si_standard == "atsc")
00914 {
00915 info.atscnum_cnt[(chan.atsc_major_channel << 16) |
00916 (chan.atsc_minor_channel)]++;
00917 info.atscmin_cnt[chan.atsc_minor_channel]++;
00918 info.atscmaj_cnt[chan.atsc_major_channel]++;
00919 }
00920 if (chan.si_standard == "ntsc")
00921 {
00922 info.atscnum_cnt[(chan.atsc_major_channel << 16) |
00923 (chan.atsc_minor_channel)]++;
00924 }
00925 }
00926 }
00927
00928 return info;
00929 }
00930
00931 ChannelImporterUniquenessStats ChannelImporter::CollectUniquenessStats(
00932 const ScanDTVTransportList &transports,
00933 const ChannelImporterBasicStats &info)
00934 {
00935 ChannelImporterUniquenessStats stats;
00936
00937 for (uint i = 0; i < transports.size(); i++)
00938 {
00939 for (uint j = 0; j < transports[i].channels.size(); j++)
00940 {
00941 const ChannelInsertInfo &chan = transports[i].channels[j];
00942 stats.unique_prognum +=
00943 (info.prognum_cnt[chan.service_id] == 1) ? 1 : 0;
00944 stats.unique_channum +=
00945 (info.channum_cnt[map_str(chan.chan_num)] == 1) ? 1 : 0;
00946
00947 if (chan.si_standard == "atsc")
00948 {
00949 stats.unique_atscnum +=
00950 (info.atscnum_cnt[(chan.atsc_major_channel << 16) |
00951 (chan.atsc_minor_channel)] == 1) ? 1 : 0;
00952 stats.unique_atscmin +=
00953 (info.atscmin_cnt[(chan.atsc_minor_channel)] == 1) ? 1 : 0;
00954 stats.max_atscmajcnt = max(
00955 stats.max_atscmajcnt,
00956 info.atscmaj_cnt[chan.atsc_major_channel]);
00957 }
00958 }
00959 }
00960
00961 stats.unique_total = (stats.unique_prognum + stats.unique_atscnum +
00962 stats.unique_atscmin + stats.unique_channum);
00963
00964 return stats;
00965 }
00966
00967
00968 QString ChannelImporter::FormatChannel(
00969 const ScanDTVTransport &transport,
00970 const ChannelInsertInfo &chan,
00971 const ChannelImporterBasicStats *info)
00972 {
00973 QString msg;
00974 QTextStream ssMsg(&msg);
00975
00976 ssMsg << transport.modulation.toString().toAscii().constData()
00977 << ":";
00978 ssMsg << transport.frequency << ":";
00979
00980 QString si_standard = (chan.si_standard=="opencable") ?
00981 QString("scte") : chan.si_standard;
00982
00983 if (si_standard == "atsc" || si_standard == "scte")
00984 ssMsg << (QString("%1:%2:%3-%4:%5:%6=%7=%8:%9")
00985 .arg(chan.callsign).arg(chan.chan_num)
00986 .arg(chan.atsc_major_channel)
00987 .arg(chan.atsc_minor_channel)
00988 .arg(chan.service_id)
00989 .arg(chan.vct_tsid)
00990 .arg(chan.vct_chan_tsid)
00991 .arg(chan.pat_tsid)
00992 .arg(si_standard)).toAscii().constData();
00993 else if (si_standard == "dvb")
00994 ssMsg << (QString("%1:%2:%3:%4:%5:%6=%7:%8")
00995 .arg(chan.service_name).arg(chan.chan_num)
00996 .arg(chan.netid).arg(chan.orig_netid)
00997 .arg(chan.service_id)
00998 .arg(chan.sdt_tsid)
00999 .arg(chan.pat_tsid)
01000 .arg(si_standard)).toAscii().constData();
01001 else
01002 ssMsg << (QString("%1:%2:%3:%4:%5")
01003 .arg(chan.callsign).arg(chan.chan_num)
01004 .arg(chan.service_id)
01005 .arg(chan.pat_tsid)
01006 .arg(si_standard)).toAscii().constData();
01007
01008 if (info)
01009 {
01010 ssMsg <<"\t"
01011 << chan.channel_id;
01012 }
01013
01014 if (info)
01015 {
01016 ssMsg << ":"
01017 << (QString("cnt(pnum:%1,channum:%2)")
01018 .arg(info->prognum_cnt[chan.service_id])
01019 .arg(info->channum_cnt[map_str(chan.chan_num)])
01020 ).toAscii().constData();
01021 if (chan.si_standard == "atsc")
01022 {
01023 ssMsg <<
01024 (QString(":atsc_cnt(tot:%1,minor:%2)")
01025 .arg(info->atscnum_cnt[
01026 (chan.atsc_major_channel << 16) |
01027 (chan.atsc_minor_channel)])
01028 .arg(info->atscmin_cnt[
01029 chan.atsc_minor_channel])
01030 ).toAscii().constData();
01031 }
01032 }
01033
01034 return msg;
01035 }
01036
01037 QString ChannelImporter::SimpleFormatChannel(
01038 const ScanDTVTransport &transport,
01039 const ChannelInsertInfo &chan)
01040 {
01041 QString msg;
01042 QTextStream ssMsg(&msg);
01043
01044 QString si_standard = (chan.si_standard=="opencable") ?
01045 QString("scte") : chan.si_standard;
01046
01047 if (si_standard == "atsc" || si_standard == "scte")
01048 {
01049
01050 if (si_standard == "atsc")
01051 ssMsg << (QString("%1-%2")
01052 .arg(chan.atsc_major_channel)
01053 .arg(chan.atsc_minor_channel)).toAscii().constData();
01054 else
01055 ssMsg << (QString("%1-%2")
01056 .arg(chan.freqid)
01057 .arg(chan.service_id)).toAscii().constData();
01058
01059 if (!chan.callsign.isEmpty())
01060 ssMsg << (QString(" (%1)")
01061 .arg(chan.callsign)).toAscii().constData();
01062 }
01063 else if (si_standard == "dvb")
01064 ssMsg << (QString("%1 (%2 %3)")
01065 .arg(chan.service_name).arg(chan.service_id)
01066 .arg(chan.netid)).toAscii().constData();
01067 else
01068 ssMsg << (QString("%1-%2")
01069 .arg(chan.freqid).arg(chan.service_id))
01070 .toAscii().constData();
01071
01072 return msg;
01073 }
01074
01075 QString ChannelImporter::FormatChannels(
01076 const ScanDTVTransportList &transports,
01077 const ChannelImporterBasicStats &info)
01078 {
01079 QString msg;
01080
01081 for (uint i = 0; i < transports.size(); i++)
01082 for (uint j = 0; j < transports[i].channels.size(); j++)
01083 msg += FormatChannel(transports[i], transports[i].channels[j],
01084 &info) + "\n";
01085
01086 return msg;
01087 }
01088
01089 QString ChannelImporter::GetSummary(
01090 uint transport_count,
01091 const ChannelImporterBasicStats &info,
01092 const ChannelImporterUniquenessStats &stats)
01093 {
01094
01095 QString msg = QObject::tr("Found %n transport(s):\n", "", transport_count);
01096 msg += QObject::tr("Channels: FTA Enc Dec\n") +
01097 QString("ATSC %1 %2 %3\n")
01098 .arg(info.atsc_channels[0],3).arg(info.atsc_channels[1],3)
01099 .arg(info.atsc_channels[2],3) +
01100 QString("DVB %1 %2 %3\n")
01101 .arg(info.dvb_channels [0],3).arg(info.dvb_channels [1],3)
01102 .arg(info.dvb_channels [2],3) +
01103 QString("SCTE %1 %2 %3\n")
01104 .arg(info.scte_channels[0],3).arg(info.scte_channels[1],3)
01105 .arg(info.scte_channels[2],3) +
01106 QString("MPEG %1 %2 %3\n")
01107 .arg(info.mpeg_channels[0],3).arg(info.mpeg_channels[1],3)
01108 .arg(info.mpeg_channels[2],3) +
01109 QString("NTSC %1\n").arg(info.ntsc_channels[0],3) +
01110 QObject::tr("Unique: prog %1 atsc %2 atsc minor %3 channum %4\n")
01111 .arg(stats.unique_prognum).arg(stats.unique_atscnum)
01112 .arg(stats.unique_atscmin).arg(stats.unique_channum) +
01113 QObject::tr("Max atsc major count: %1")
01114 .arg(stats.max_atscmajcnt);
01115
01116 return msg;
01117 }
01118
01119 bool ChannelImporter::IsType(
01120 const ChannelImporterBasicStats &info,
01121 const ChannelInsertInfo &chan, ChannelType type)
01122 {
01123 switch (type)
01124 {
01125 case kATSCNonConflicting:
01126 return ((chan.si_standard == "atsc") &&
01127 (info.atscnum_cnt[(chan.atsc_major_channel << 16) |
01128 (chan.atsc_minor_channel)] == 1));
01129
01130 case kDVBNonConflicting:
01131 return ((chan.si_standard == "dvb") &&
01132 (info.prognum_cnt[chan.service_id] == 1));
01133
01134 case kMPEGNonConflicting:
01135 return ((chan.si_standard == "mpeg") &&
01136 (info.channum_cnt[map_str(chan.chan_num)] == 1));
01137
01138 case kSCTENonConflicting:
01139 return (((chan.si_standard == "scte") ||
01140 (chan.si_standard == "opencable")) &&
01141 (info.channum_cnt[map_str(chan.chan_num)] == 1));
01142
01143 case kNTSCNonConflicting:
01144 return ((chan.si_standard == "ntsc") &&
01145 (info.atscnum_cnt[(chan.atsc_major_channel << 16) |
01146 (chan.atsc_minor_channel)] == 1));
01147
01148 case kATSCConflicting:
01149 return ((chan.si_standard == "atsc") &&
01150 (info.atscnum_cnt[(chan.atsc_major_channel << 16) |
01151 (chan.atsc_minor_channel)] != 1));
01152
01153 case kDVBConflicting:
01154 return ((chan.si_standard == "dvb") &&
01155 (info.prognum_cnt[chan.service_id] != 1));
01156
01157 case kMPEGConflicting:
01158 return ((chan.si_standard == "mpeg") &&
01159 (info.channum_cnt[map_str(chan.chan_num)] != 1));
01160
01161 case kSCTEConflicting:
01162 return (((chan.si_standard == "scte") ||
01163 (chan.si_standard == "opencable")) &&
01164 (info.channum_cnt[map_str(chan.chan_num)] != 1));
01165
01166 case kNTSCConflicting:
01167 return ((chan.si_standard == "ntsc") &&
01168 (info.atscnum_cnt[(chan.atsc_major_channel << 16) |
01169 (chan.atsc_minor_channel)] != 1));
01170 }
01171 return false;
01172 }
01173
01174 void ChannelImporter::CountChannels(
01175 const ScanDTVTransportList &transports,
01176 const ChannelImporterBasicStats &info,
01177 ChannelType type, uint &new_chan, uint &old_chan)
01178 {
01179 new_chan = old_chan = 0;
01180 for (uint i = 0; i < transports.size(); i++)
01181 {
01182 for (uint j = 0; j < transports[i].channels.size(); j++)
01183 {
01184 ChannelInsertInfo chan = transports[i].channels[j];
01185 if (IsType(info, chan, type))
01186 {
01187 if (chan.channel_id)
01188 old_chan++;
01189 else
01190 new_chan++;
01191 }
01192 }
01193 }
01194 }
01195
01196 QString ChannelImporter::ComputeSuggestedChannelNum(
01197 const ChannelImporterBasicStats &info,
01198 const ScanDTVTransport &transport,
01199 const ChannelInsertInfo &chan)
01200 {
01201 static QMutex last_free_lock;
01202 static QMap<uint,uint> last_free_chan_num_map;
01203
01204 QString channelFormat = "%1_%2";
01205 QString chan_num = channelFormat
01206 .arg(chan.atsc_major_channel)
01207 .arg(chan.atsc_minor_channel);
01208
01209 if (!chan.atsc_minor_channel)
01210 {
01211 if (chan.si_standard == "dvb")
01212 {
01213 chan_num = QString("%1")
01214 .arg(chan.service_id);
01215 }
01216 else
01217 chan_num = QString("%1-%2")
01218 .arg(chan.freqid)
01219 .arg(chan.service_id);
01220 }
01221
01222 if (!ChannelUtil::IsConflicting(chan_num, chan.source_id))
01223 return chan_num;
01224
01225 QMutexLocker locker(&last_free_lock);
01226 uint last_free_chan_num = last_free_chan_num_map[chan.source_id];
01227 for (last_free_chan_num++; ; last_free_chan_num++)
01228 {
01229 chan_num = QString::number(last_free_chan_num);
01230 if (!ChannelUtil::IsConflicting(chan_num, chan.source_id))
01231 break;
01232 }
01233 last_free_chan_num_map[chan.source_id] = last_free_chan_num;
01234
01235 return chan_num;
01236 }
01237
01238 ChannelImporter::DeleteAction
01239 ChannelImporter::QueryUserDelete(const QString &msg)
01240 {
01241 DeleteAction action = kDeleteAll;
01242 if (use_gui)
01243 {
01244 QStringList buttons;
01245 buttons.push_back(QObject::tr("Delete all"));
01246 buttons.push_back(QObject::tr("Set all invisible"));
01247
01248 buttons.push_back(QObject::tr("Ignore all"));
01249
01250 DialogCode ret;
01251 do
01252 {
01253 ret = MythPopupBox::ShowButtonPopup(
01254 GetMythMainWindow(), QObject::tr("Channel Importer"),
01255 msg, buttons, kDialogCodeButton0);
01256
01257 ret = (kDialogCodeRejected == ret) ? kDialogCodeButton2 : ret;
01258
01259 } while (!(kDialogCodeButton0 <= ret && ret <= kDialogCodeButton3));
01260
01261 action = (kDialogCodeButton0 == ret) ? kDeleteAll : action;
01262 action = (kDialogCodeButton1 == ret) ? kDeleteInvisibleAll : action;
01263 action = (kDialogCodeButton2 == ret) ? kDeleteIgnoreAll : action;
01264
01265
01266 }
01267 else if (is_interactive)
01268 {
01269 cout << msg.toAscii().constData() << endl;
01270 cout << "Do you want to:" << endl;
01271 cout << "1. Delete all" << endl;
01272 cout << "2. Set all invisible" << endl;
01273
01274 cout << "4. Ignore all" << endl;
01275 while (true)
01276 {
01277 string ret;
01278 cin >> ret;
01279 bool ok;
01280 uint val = QString(ret.c_str()).toUInt(&ok);
01281 if (ok && (1 <= val) && (val <= 3))
01282 {
01283 action = (1 == val) ? kDeleteAll : action;
01284 action = (2 == val) ? kDeleteInvisibleAll : action;
01285
01286 action = (3 == val) ? kDeleteIgnoreAll : action;
01287 action = (4 == val) ? kDeleteIgnoreAll : action;
01288 break;
01289 }
01290 else
01291 {
01292
01293 cout << "Please enter either 1, 2 or 4:" << endl;
01294 }
01295 }
01296 }
01297
01298 return action;
01299 }
01300
01301 ChannelImporter::InsertAction
01302 ChannelImporter::QueryUserInsert(const QString &msg)
01303 {
01304 InsertAction action = kInsertAll;
01305 if (use_gui)
01306 {
01307 QStringList buttons;
01308 buttons.push_back(QObject::tr("Insert all"));
01309 buttons.push_back(QObject::tr("Insert manually"));
01310 buttons.push_back(QObject::tr("Ignore all"));
01311
01312 DialogCode ret;
01313 do
01314 {
01315 ret = MythPopupBox::ShowButtonPopup(
01316 GetMythMainWindow(), QObject::tr("Channel Importer"),
01317 msg, buttons, kDialogCodeButton0);
01318
01319 ret = (kDialogCodeRejected == ret) ? kDialogCodeButton2 : ret;
01320
01321 } while (!(kDialogCodeButton0 <= ret && ret <= kDialogCodeButton2));
01322
01323 action = (kDialogCodeButton0 == ret) ? kInsertAll : action;
01324 action = (kDialogCodeButton1 == ret) ? kInsertManual : action;
01325 action = (kDialogCodeButton2 == ret) ? kInsertIgnoreAll : action;
01326 }
01327 else if (is_interactive)
01328 {
01329 cout << msg.toAscii().constData() << endl;
01330 cout << "Do you want to:" << endl;
01331 cout << "1. Insert all" << endl;
01332 cout << "2. Insert manually" << endl;
01333 cout << "3. Ignore all" << endl;
01334 while (true)
01335 {
01336 string ret;
01337 cin >> ret;
01338 bool ok;
01339 uint val = QString(ret.c_str()).toUInt(&ok);
01340 if (ok && (1 <= val) && (val <= 3))
01341 {
01342 action = (1 == val) ? kInsertAll : action;
01343 action = (2 == val) ? kInsertManual : action;
01344 action = (3 == val) ? kInsertIgnoreAll : action;
01345 break;
01346 }
01347 else
01348 {
01349 cout << "Please enter either 1, 2, or 3:" << endl;
01350 }
01351 }
01352 }
01353
01354 return action;
01355 }
01356
01357 ChannelImporter::UpdateAction
01358 ChannelImporter::QueryUserUpdate(const QString &msg)
01359 {
01360 UpdateAction action = kUpdateAll;
01361
01362 if (use_gui)
01363 {
01364 QStringList buttons;
01365 buttons.push_back(QObject::tr("Update all"));
01366 buttons.push_back(QObject::tr("Update manually"));
01367 buttons.push_back(QObject::tr("Ignore all"));
01368
01369 DialogCode ret;
01370 do
01371 {
01372 ret = MythPopupBox::ShowButtonPopup(
01373 GetMythMainWindow(), QObject::tr("Channel Importer"),
01374 msg, buttons, kDialogCodeButton0);
01375
01376 ret = (kDialogCodeRejected == ret) ? kDialogCodeButton2 : ret;
01377
01378 } while (!(kDialogCodeButton0 <= ret && ret <= kDialogCodeButton2));
01379
01380 action = (kDialogCodeButton0 == ret) ? kUpdateAll : action;
01381 action = (kDialogCodeButton1 == ret) ? kUpdateManual : action;
01382 action = (kDialogCodeButton2 == ret) ? kUpdateIgnoreAll : action;
01383 }
01384 else if (is_interactive)
01385 {
01386 cout << msg.toAscii().constData()
01387 << endl
01388 << QObject::tr("Do you want to:").toAscii().constData()
01389 << endl
01390 << "1. " << QObject::tr("Update all").toAscii().constData()
01391 << endl
01392 << "2. " << QObject::tr("Update manually").toAscii().constData()
01393 << endl
01394 << "3. " << QObject::tr("Ignore all").toAscii().constData()
01395 << endl;
01396 while (true)
01397 {
01398 string ret;
01399 cin >> ret;
01400 bool ok;
01401 uint val = QString(ret.c_str()).toUInt(&ok);
01402 if (ok && (1 <= val) && (val <= 3))
01403 {
01404 action = (1 == val) ? kUpdateAll : action;
01405 action = (2 == val) ? kUpdateManual : action;
01406 action = (3 == val) ? kUpdateIgnoreAll : action;
01407 break;
01408 }
01409 else
01410 {
01411 cout << QObject::tr(
01412 "Please enter either 1, 2, or 3:")
01413 .toAscii().constData() << endl;
01414 }
01415 }
01416 }
01417
01418 return action;
01419 }
01420
01421 OkCancelType ChannelImporter::ShowManualChannelPopup(
01422 MythMainWindow *parent, QString title,
01423 QString message, QString &text)
01424 {
01425 MythPopupBox *popup = new MythPopupBox(parent, title.toAscii().constData());
01426
01427 popup->addLabel(message, MythPopupBox::Medium, true);
01428
01429 MythLineEdit *textEdit = new MythLineEdit(popup);
01430
01431 QString orig_text = text;
01432 text = "";
01433 textEdit->setText(text);
01434 popup->addWidget(textEdit);
01435
01436 popup->addButton(QObject::tr("OK"), popup, SLOT(accept()));
01437 popup->addButton(QObject::tr("Suggest"));
01438 popup->addButton(QObject::tr("Cancel"), popup, SLOT(reject()));
01439 popup->addButton(QObject::tr("Cancel All"));
01440
01441 textEdit->setFocus();
01442
01443 DialogCode dc = popup->ExecPopup();
01444 if (kDialogCodeButton1 == dc)
01445 {
01446 popup->hide();
01447 popup->deleteLater();
01448
01449 popup = new MythPopupBox(parent, title.toAscii().constData());
01450 popup->addLabel(message, MythPopupBox::Medium, true);
01451
01452 textEdit = new MythLineEdit(popup);
01453
01454 text = orig_text;
01455 textEdit->setText(text);
01456 popup->addWidget(textEdit);
01457
01458 popup->addButton(QObject::tr("OK"), popup, SLOT(accept()))->setFocus();
01459 popup->addButton(QObject::tr("Cancel"), popup, SLOT(reject()));
01460 popup->addButton(QObject::tr("Cancel All"));
01461
01462 dc = popup->ExecPopup();
01463 }
01464
01465 bool ok = (kDialogCodeAccepted == dc);
01466 if (ok)
01467 text = textEdit->text();
01468
01469 popup->hide();
01470 popup->deleteLater();
01471
01472 return (ok) ? kOCTOk :
01473 ((kDialogCodeRejected == dc) ? kOCTCancel : kOCTCancelAll);
01474 }
01475
01476 OkCancelType ChannelImporter::QueryUserResolve(
01477 const ChannelImporterBasicStats &info,
01478 const ScanDTVTransport &transport,
01479 ChannelInsertInfo &chan)
01480 {
01481 QString msg = QObject::tr(
01482 "Channel %1 was found to be in conflict with other channels. ")
01483 .arg(SimpleFormatChannel(transport, chan));
01484
01485 OkCancelType ret = kOCTCancel;
01486
01487 if (use_gui)
01488 {
01489 while (true)
01490 {
01491 QString msg2 = msg;
01492 msg2 += QObject::tr("Please enter a unique channel number. ");
01493
01494 QString val = ComputeSuggestedChannelNum(info, transport, chan);
01495 ret = ShowManualChannelPopup(
01496 GetMythMainWindow(), QObject::tr("Channel Importer"),
01497 msg2, val);
01498
01499 if (kOCTOk != ret)
01500 break;
01501
01502 bool ok = (val.length() >= 1);
01503 ok = ok && ((val[0] >= '0') && (val[0] <= '9'));
01504 ok = ok && !ChannelUtil::IsConflicting(
01505 val, chan.source_id, chan.channel_id);
01506
01507 chan.chan_num = (ok) ? val : chan.chan_num;
01508 if (ok)
01509 break;
01510 }
01511 }
01512 else if (is_interactive)
01513 {
01514 cout << msg.toAscii().constData() << endl;
01515
01516 QString cancelStr = QObject::tr("Cancel").toLower();
01517 QString cancelAllStr = QObject::tr("Cancel All").toLower();
01518 QString msg2 = QObject::tr(
01519 "Please enter a non-conflicting channel number "
01520 "(or type %1 to skip, %2 to skip all): ")
01521 .arg(cancelStr).arg(cancelAllStr);
01522
01523 while (true)
01524 {
01525 cout << msg2.toAscii().constData() << endl;
01526 string sret;
01527 cin >> sret;
01528 QString val = QString(sret.c_str());
01529 if (val.toLower() == cancelStr)
01530 {
01531 ret = kOCTCancel;
01532 break;
01533 }
01534 if (val.toLower() == cancelAllStr)
01535 {
01536 ret = kOCTCancelAll;
01537 break;
01538 }
01539
01540 bool ok = (val.length() >= 1);
01541 ok = ok && ((val[0] >= '0') && (val[0] <= '9'));
01542 ok = ok && !ChannelUtil::IsConflicting(
01543 val, chan.source_id, chan.channel_id);
01544
01545 chan.chan_num = (ok) ? val : chan.chan_num;
01546 if (ok)
01547 {
01548 ret = kOCTOk;
01549 break;
01550 }
01551 }
01552 }
01553
01554 return ret;
01555 }
01556
01557 OkCancelType ChannelImporter::QueryUserInsert(
01558 const ChannelImporterBasicStats &info,
01559 const ScanDTVTransport &transport,
01560 ChannelInsertInfo &chan)
01561 {
01562 QString msg = QObject::tr(
01563 "You chose to manually insert channel %1.")
01564 .arg(SimpleFormatChannel(transport, chan));
01565
01566 OkCancelType ret = kOCTCancel;
01567
01568 if (use_gui)
01569 {
01570 while (true)
01571 {
01572 QString msg2 = msg;
01573 msg2 += QObject::tr("Please enter a unique channel number. ");
01574
01575 QString val = ComputeSuggestedChannelNum(info, transport, chan);
01576 ret = ShowManualChannelPopup(
01577 GetMythMainWindow(), QObject::tr("Channel Importer"),
01578 msg2, val);
01579
01580 if (kOCTOk != ret)
01581 break;
01582
01583 bool ok = (val.length() >= 1);
01584 ok = ok && ((val[0] >= '0') && (val[0] <= '9'));
01585 ok = ok && !ChannelUtil::IsConflicting(
01586 val, chan.source_id, chan.channel_id);
01587
01588 chan.chan_num = (ok) ? val : chan.chan_num;
01589 if (ok)
01590 {
01591 ret = kOCTOk;
01592 break;
01593 }
01594 }
01595 }
01596 else if (is_interactive)
01597 {
01598 cout << msg.toAscii().constData() << endl;
01599
01600 QString cancelStr = QObject::tr("Cancel").toLower();
01601 QString cancelAllStr = QObject::tr("Cancel All").toLower();
01602 QString msg2 = QObject::tr(
01603 "Please enter a non-conflicting channel number "
01604 "(or type %1 to skip, %2 to skip all): ")
01605 .arg(cancelStr).arg(cancelAllStr);
01606
01607 while (true)
01608 {
01609 cout << msg2.toAscii().constData() << endl;
01610 string sret;
01611 cin >> sret;
01612 QString val = QString(sret.c_str());
01613 if (val.toLower() == cancelStr)
01614 {
01615 ret = kOCTCancel;
01616 break;
01617 }
01618 if (val.toLower() == cancelAllStr)
01619 {
01620 ret = kOCTCancelAll;
01621 break;
01622 }
01623
01624 bool ok = (val.length() >= 1);
01625 ok = ok && ((val[0] >= '0') && (val[0] <= '9'));
01626 ok = ok && !ChannelUtil::IsConflicting(
01627 val, chan.source_id, chan.channel_id);
01628
01629 chan.chan_num = (ok) ? val : chan.chan_num;
01630 if (ok)
01631 {
01632 ret = kOCTOk;
01633 break;
01634 }
01635 }
01636 }
01637
01638 return ret;
01639 }