00001
00002
00003 #include <algorithm>
00004 #include <set>
00005 using namespace std;
00006
00007 #include <qdeepcopy.h>
00008 #include <qregexp.h>
00009 #include <stdint.h>
00010 #include <qimage.h>
00011 #include <qfile.h>
00012
00013 #include "channelutil.h"
00014 #include "mythdbcon.h"
00015 #include "dvbtables.h"
00016 #include "tv.h"
00017
00018 #define LOC QString("ChanUtil: ")
00019 #define LOC_ERR QString("ChanUtil, Error: ")
00020
00021 DBChannel::DBChannel(const DBChannel &other)
00022 {
00023 (*this) = other;
00024 }
00025
00026 DBChannel::DBChannel(
00027 const QString &_channum, const QString &_callsign,
00028 uint _chanid, uint _major_chan, uint _minor_chan,
00029 uint _favorite, uint _mplexid, bool _visible,
00030 const QString &_name, const QString &_icon) :
00031 channum(QDeepCopy<QString>(_channum)),
00032 callsign(QDeepCopy<QString>(_callsign)),
00033 chanid(_chanid), major_chan(_major_chan), minor_chan(_minor_chan),
00034 favorite(_favorite), mplexid(_mplexid), visible(_visible),
00035 name(QDeepCopy<QString>(_name)),
00036 icon(QDeepCopy<QString>(_icon))
00037 {
00038 mplexid = (mplexid == 32767) ? 0 : mplexid;
00039 icon = (icon == "none") ? QString::null : icon;
00040 }
00041
00042 DBChannel& DBChannel::operator=(const DBChannel &other)
00043 {
00044 channum = QDeepCopy<QString>(other.channum);
00045 callsign = QDeepCopy<QString>(other.callsign);
00046 chanid = other.chanid;
00047 major_chan = other.major_chan;
00048 minor_chan = other.minor_chan;
00049 favorite = other.favorite;
00050 mplexid = (other.mplexid == 32767) ? 0 : other.mplexid;
00051 visible = other.visible;
00052 name = QDeepCopy<QString>(other.name);
00053 icon = QDeepCopy<QString>(other.icon);
00054
00055 return *this;
00056 }
00057
00058 bool PixmapChannel::LoadChannelIcon(uint size) const
00059 {
00060 if (!size || size > 3000)
00061 return false;
00062
00063 QImage tempimage(icon);
00064
00065 if (tempimage.width() == 0)
00066 {
00067 QFile existtest(icon);
00068
00069
00070 if (existtest.exists())
00071 return false;
00072
00073 QString url = gContext->GetMasterHostPrefix();
00074 if (url.length() < 1)
00075 return false;
00076
00077 url += icon;
00078
00079 QImage *cached = gContext->CacheRemotePixmap(url);
00080 if (cached)
00081 tempimage = *cached;
00082 }
00083
00084 if (tempimage.width() > 0)
00085 {
00086 iconLoaded = true;
00087 if ((tempimage.width() != (int) size) ||
00088 (tempimage.height() != (int) size))
00089 {
00090 QImage tmp2;
00091 tmp2 = tempimage.smoothScale(size, size);
00092 iconPixmap.convertFromImage(tmp2);
00093 }
00094 else
00095 iconPixmap.convertFromImage(tempimage);
00096 }
00097
00098 return iconLoaded;
00099 }
00100
00101 QString PixmapChannel::GetFormatted(const QString &format) const
00102 {
00103 QString tmp = format;
00104
00105 if (tmp.isEmpty())
00106 return "";
00107
00108 tmp.replace("<num>", channum);
00109 tmp.replace("<sign>", callsign);
00110 tmp.replace("<name>", name);
00111
00112 return tmp;
00113 }
00114
00115 static uint get_dtv_multiplex(int db_source_id, QString sistandard,
00116 uint frequency,
00117
00118 int transport_id, int network_id)
00119 {
00120 QString qstr =
00121 "SELECT mplexid "
00122 "FROM dtv_multiplex "
00123 "WHERE sourceid = :SOURCEID "
00124 " AND sistandard = :SISTANDARD ";
00125
00126 if (sistandard.lower() != "dvb")
00127 qstr += "AND frequency = :FREQUENCY ";
00128 else
00129 {
00130 qstr += "AND transportid = :TRANSPORTID ";
00131 qstr += "AND networkid = :NETWORKID ";
00132 }
00133
00134 MSqlQuery query(MSqlQuery::InitCon());
00135 query.prepare(qstr);
00136
00137 query.bindValue(":SOURCEID", db_source_id);
00138 query.bindValue(":SISTANDARD", sistandard);
00139
00140 if (sistandard.lower() != "dvb")
00141 query.bindValue(":FREQUENCY", frequency);
00142 else
00143 {
00144 query.bindValue(":TRANSPORTID", transport_id);
00145 query.bindValue(":NETWORKID", network_id);
00146 }
00147
00148 if (!query.exec() || !query.isActive())
00149 {
00150 MythContext::DBError("get_dtv_multiplex", query);
00151 return 0;
00152 }
00153
00154 if (query.next())
00155 return query.value(0).toUInt();
00156
00157 return 0;
00158 }
00159
00160 static uint insert_dtv_multiplex(
00161 int db_source_id, QString sistandard,
00162 uint frequency, QString modulation,
00163
00164 int transport_id, int network_id,
00165 int symbol_rate, signed char bandwidth,
00166 signed char polarity, signed char inversion,
00167 signed char trans_mode,
00168 QString inner_FEC, QString constellation,
00169 signed char hierarchy, QString hp_code_rate,
00170 QString lp_code_rate, QString guard_interval)
00171 {
00172 MSqlQuery query(MSqlQuery::InitCon());
00173
00174 VERBOSE(VB_SIPARSER, QString("insert_dtv_multiplex(%1, %2, %3, %4...)")
00175 .arg(db_source_id).arg(sistandard)
00176 .arg(frequency).arg(modulation));
00177
00178
00179 int mplex = get_dtv_multiplex(
00180 db_source_id, sistandard, frequency,
00181
00182 transport_id, network_id);
00183
00184 QString updateStr =
00185 "UPDATE dtv_multiplex "
00186 "SET sourceid = :SOURCEID, sistandard = :SISTANDARD, "
00187 " frequency = :FREQUENCY, modulation = :MODULATION, "
00188 " transportid = :TRANSPORTID, networkid = :NETWORKID, "
00189 " symbolrate = :SYMBOLRATE, bandwidth = :BANDWIDTH, "
00190 " polarity = :POLARITY, inversion = :INVERSION, "
00191 " transmission_mode= :TRANS_MODE, fec = :INNER_FEC, "
00192 " constellation = :CONSTELLATION, hierarchy = :HIERARCHY, "
00193 " hp_code_rate = :HP_CODE_RATE, lp_code_rate = :LP_CODE_RATE, "
00194 " guard_interval = :GUARD_INTERVAL "
00195 "WHERE sourceid = :SOURCEID AND "
00196 " sistandard = :SISTANDARD AND "
00197 " transportid = :TRANSPORTID AND "
00198 " networkid = :NETWORKID ";
00199
00200 if (sistandard.lower() != "dvb")
00201 updateStr += " AND frequency = :FREQUENCY ";
00202
00203 QString insertStr =
00204 "INSERT INTO dtv_multiplex "
00205 " (sourceid, sistandard, frequency, "
00206 " modulation, transportid, networkid, "
00207 " symbolrate, bandwidth, polarity, "
00208 " inversion, transmission_mode, "
00209 " fec, constellation, hierarchy, "
00210 " hp_code_rate, lp_code_rate, guard_interval) "
00211 "VALUES "
00212 " (:SOURCEID, :SISTANDARD, :FREQUENCY, "
00213 " :MODULATION, :TRANSPORTID, :NETWORKID, "
00214 " :SYMBOLRATE, :BANDWIDTH, :POLARITY, "
00215 " :INVERSION, :TRANS_MODE, "
00216 " :INNER_FEC, :CONSTELLATION, :HIERARCHY, "
00217 " :HP_CODE_RATE, :LP_CODE_RATE, :GUARD_INTERVAL);";
00218
00219 query.prepare((mplex) ? updateStr : insertStr);
00220
00221 VERBOSE(VB_SIPARSER, "insert_dtv_multiplex -- "
00222 <<((mplex) ? "update" : "insert") << " " << mplex);
00223
00224 query.bindValue(":SOURCEID", db_source_id);
00225 query.bindValue(":SISTANDARD", sistandard);
00226 query.bindValue(":FREQUENCY", frequency);
00227
00228 if (!modulation.isNull())
00229 query.bindValue(":MODULATION", modulation);
00230 if (sistandard.lower() == "dvb")
00231 {
00232 query.bindValue(":TRANSPORTID", transport_id);
00233 query.bindValue(":NETWORKID", network_id);
00234 }
00235 if (symbol_rate >= 0)
00236 query.bindValue(":SYMBOLRATE", symbol_rate);
00237 if (bandwidth >= 0)
00238 query.bindValue(":BANDWIDTH", QString("%1").arg((char)bandwidth));
00239 if (polarity >= 0)
00240 query.bindValue(":POLARITY", QString("%1").arg((char)polarity));
00241 if (inversion >= 0)
00242 query.bindValue(":INVERSION", QString("%1").arg((char)inversion));
00243 if (trans_mode >= 0)
00244 query.bindValue(":TRANS_MODE", QString("%1").arg((char)trans_mode));
00245
00246 if (!inner_FEC.isNull())
00247 query.bindValue(":INNER_FEC", inner_FEC);
00248 if (!constellation.isNull())
00249 query.bindValue(":CONSTELLATION", constellation);
00250 if (hierarchy >= 0)
00251 query.bindValue(":HIERARCHY", QString("%1").arg((char)hierarchy));
00252 if (!hp_code_rate.isNull())
00253 query.bindValue(":HP_CODE_RATE", hp_code_rate);
00254 if (!lp_code_rate.isNull())
00255 query.bindValue(":LP_CODE_RATE", lp_code_rate);
00256 if (!guard_interval.isNull())
00257 query.bindValue(":GUARD_INTERVAL",guard_interval);
00258
00259 if (!query.exec() || !query.isActive())
00260 {
00261 MythContext::DBError("Adding transport to Database.", query);
00262 return 0;
00263 }
00264
00265 if (mplex)
00266 return mplex;
00267
00268 mplex = get_dtv_multiplex(
00269 db_source_id, sistandard, frequency,
00270
00271 transport_id, network_id);
00272
00273 VERBOSE(VB_SIPARSER, QString("insert_dtv_multiplex -- ") +
00274 QString("inserted %1").arg(mplex));
00275
00276 return mplex;
00277 }
00278
00279 void handle_transport_desc(vector<uint> &muxes, const MPEGDescriptor &desc,
00280 uint sourceid, uint tsid, uint netid)
00281 {
00282 uint tag = desc.DescriptorTag();
00283
00284 if (tag == DescriptorID::terrestrial_delivery_system)
00285 {
00286 const TerrestrialDeliverySystemDescriptor cd(desc);
00287 uint64_t freq = cd.FrequencyHz();
00288
00289 if (!freq)
00290 return;
00291
00292
00293
00294 int mux = ChannelUtil::GetMplexID(sourceid, tsid, netid);
00295 if (mux > 0)
00296 {
00297 QString dummy_mod;
00298 QString dummy_sistd;
00299 uint dummy_tsid, dummy_netid;
00300 ChannelUtil::GetTuningParams(mux, dummy_mod, freq,
00301 dummy_tsid, dummy_netid, dummy_sistd);
00302 }
00303
00304 mux = ChannelUtil::CreateMultiplex(
00305 sourceid, "dvb",
00306 freq, QString::null,
00307
00308 tsid, netid,
00309 -1, QChar(cd.BandwidthString()[0]),
00310 -1, 'a',
00311 QChar(cd.TransmissionModeString()[0]),
00312 QString::null, cd.ConstellationString(),
00313 QChar(cd.HierarchyString()[0]), cd.CodeRateHPString(),
00314 cd.CodeRateLPString(), cd.GuardIntervalString());
00315
00316 if (mux)
00317 muxes.push_back(mux);
00318
00319
00320
00321
00322
00323
00324
00325
00326 }
00327 else if (tag == DescriptorID::satellite_delivery_system)
00328 {
00329 const SatelliteDeliverySystemDescriptor cd(desc);
00330
00331 if (!cd.FrequencyHz())
00332 return;
00333
00334 uint mux = ChannelUtil::CreateMultiplex(
00335 sourceid, "dvb",
00336 cd.FrequencyHz(), cd.ModulationString(),
00337
00338 tsid, netid,
00339 cd.SymbolRateHz(), -1,
00340 QChar(cd.PolarizationString()[0]), 'a',
00341 -1,
00342 cd.FECInnerString(), QString::null,
00343 -1, QString::null,
00344 QString::null, QString::null);
00345
00346 if (mux)
00347 muxes.push_back(mux);
00348
00349
00350
00351
00352 }
00353 else if (tag == DescriptorID::cable_delivery_system)
00354 {
00355 const CableDeliverySystemDescriptor cd(desc);
00356
00357 if (!cd.FrequencyHz())
00358 return;
00359
00360 uint mux = ChannelUtil::CreateMultiplex(
00361 sourceid, "dvb",
00362 cd.FrequencyHz(), cd.ModulationString(),
00363
00364 tsid, netid,
00365 cd.SymbolRateHz(), -1,
00366 -1, 'a',
00367 -1,
00368 cd.FECInnerString(), QString::null,
00369 -1, QString::null,
00370 QString::null, QString::null);
00371
00372 if (mux)
00373 muxes.push_back(mux);
00374 }
00375 }
00376
00377 uint ChannelUtil::CreateMultiplex(int sourceid, QString sistandard,
00378 uint frequency, QString modulation,
00379 int transport_id, int network_id)
00380 {
00381 return CreateMultiplex(
00382 sourceid, sistandard,
00383 frequency, modulation,
00384 transport_id, network_id,
00385 -1, -1,
00386 -1, -1,
00387 -1,
00388 QString::null, QString::null,
00389 -1, QString::null,
00390 QString::null, QString::null);
00391 }
00392
00393 uint ChannelUtil::CreateMultiplex(
00394 int sourceid, QString sistandard,
00395 uint freq, QString modulation,
00396
00397 int transport_id, int network_id,
00398 int symbol_rate, signed char bandwidth,
00399 signed char polarity, signed char inversion,
00400 signed char trans_mode,
00401 QString inner_FEC, QString constellation,
00402 signed char hierarchy, QString hp_code_rate,
00403 QString lp_code_rate, QString guard_interval)
00404 {
00405 return insert_dtv_multiplex(
00406 sourceid, sistandard,
00407 freq, modulation,
00408
00409 transport_id, network_id,
00410 symbol_rate, bandwidth,
00411 polarity, inversion,
00412 trans_mode,
00413 inner_FEC, constellation,
00414 hierarchy, hp_code_rate,
00415 lp_code_rate, guard_interval);
00416 }
00417
00418 uint ChannelUtil::CreateMultiplex(uint sourceid, const DTVMultiplex &mux,
00419 int transport_id, int network_id)
00420 {
00421 return insert_dtv_multiplex(
00422 sourceid, mux.sistandard,
00423 mux.frequency, mux.modulation.toString(),
00424
00425 transport_id, network_id,
00426 mux.symbolrate, mux.bandwidth.toChar(),
00427 mux.polarity.toChar(), mux.inversion.toChar(),
00428 mux.trans_mode.toChar(),
00429 mux.fec.toString(), mux.modulation.toString(),
00430 mux.hierarchy.toChar(), mux.hp_code_rate.toString(),
00431 mux.lp_code_rate.toString(), mux.guard_interval.toString());
00432 }
00433
00434
00438 vector<uint> ChannelUtil::CreateMultiplexes(
00439 int sourceid, const NetworkInformationTable *nit)
00440 {
00441 vector<uint> muxes;
00442
00443 if (sourceid <= 0)
00444 return muxes;
00445
00446 for (uint i = 0; i < nit->TransportStreamCount(); ++i)
00447 {
00448 const desc_list_t& list =
00449 MPEGDescriptor::Parse(nit->TransportDescriptors(i),
00450 nit->TransportDescriptorsLength(i));
00451
00452 uint tsid = nit->TSID(i);
00453 uint netid = nit->OriginalNetworkID(i);
00454 for (uint j = 0; j < list.size(); ++j)
00455 {
00456 const MPEGDescriptor desc(list[j]);
00457 handle_transport_desc(muxes, desc, sourceid, tsid, netid);
00458 }
00459 }
00460 return muxes;
00461 }
00462
00463 uint ChannelUtil::GetMplexID(uint sourceid, const QString &channum)
00464 {
00465 MSqlQuery query(MSqlQuery::InitCon());
00466
00467 query.prepare(
00468 "SELECT mplexid "
00469 "FROM channel "
00470 "WHERE sourceid = :SOURCEID AND "
00471 " channum = :CHANNUM");
00472
00473 query.bindValue(":SOURCEID", sourceid);
00474 query.bindValue(":CHANNUM", channum);
00475
00476 if (!query.exec() || !query.isActive())
00477 MythContext::DBError("GetMplexID 0", query);
00478 else if (query.next())
00479 return query.value(0).toInt();
00480
00481 return 0;
00482 }
00483
00484 int ChannelUtil::GetMplexID(uint sourceid, uint frequency)
00485 {
00486 MSqlQuery query(MSqlQuery::InitCon());
00487
00488 query.prepare(
00489 "SELECT mplexid "
00490 "FROM dtv_multiplex "
00491 "WHERE sourceid = :SOURCEID AND "
00492 " frequency = :FREQUENCY");
00493
00494 query.bindValue(":SOURCEID", sourceid);
00495 query.bindValue(":FREQUENCY", frequency);
00496
00497 if (!query.exec() || !query.isActive())
00498 {
00499 MythContext::DBError("GetMplexID 1", query);
00500 return -1;
00501 }
00502
00503 if (query.next())
00504 return query.value(0).toInt();
00505
00506 return -1;
00507 }
00508
00509 int ChannelUtil::GetMplexID(uint sourceid, uint frequency,
00510 uint transport_id, uint network_id)
00511 {
00512 MSqlQuery query(MSqlQuery::InitCon());
00513
00514 query.prepare(
00515 "SELECT mplexid "
00516 "FROM dtv_multiplex "
00517 "WHERE networkid = :NETWORKID AND "
00518 " transportid = :TRANSPORTID AND "
00519 " frequency = :FREQUENCY AND "
00520 " sourceid = :SOURCEID");
00521
00522 query.bindValue(":SOURCEID", sourceid);
00523 query.bindValue(":NETWORKID", network_id);
00524 query.bindValue(":TRANSPORTID", transport_id);
00525 query.bindValue(":FREQUENCY", frequency);
00526
00527 if (!query.exec() || !query.isActive())
00528 {
00529 MythContext::DBError("GetMplexID 2", query);
00530 return -1;
00531 }
00532
00533 if (query.next())
00534 return query.value(0).toInt();
00535
00536 return -1;
00537 }
00538
00539 int ChannelUtil::GetMplexID(uint sourceid,
00540 uint transport_id, uint network_id)
00541 {
00542 MSqlQuery query(MSqlQuery::InitCon());
00543
00544 query.prepare(
00545 "SELECT mplexid "
00546 "FROM dtv_multiplex "
00547 "WHERE networkid = :NETWORKID AND "
00548 " transportid = :TRANSPORTID AND "
00549 " sourceid = :SOURCEID");
00550
00551 query.bindValue(":SOURCEID", sourceid);
00552 query.bindValue(":NETWORKID", network_id);
00553 query.bindValue(":TRANSPORTID", transport_id);
00554
00555 if (!query.exec() || !query.isActive())
00556 {
00557 MythContext::DBError("GetMplexID 3", query);
00558 return -1;
00559 }
00560
00561 if (query.next())
00562 return query.value(0).toInt();
00563
00564 return -1;
00565 }
00566
00567 uint ChannelUtil::GetMplexID(uint chanid)
00568 {
00569 MSqlQuery query(MSqlQuery::InitCon());
00570
00571 query.prepare(
00572 "SELECT mplexid "
00573 "FROM channel "
00574 "WHERE chanid = :CHANID");
00575
00576 query.bindValue(":CHANID", chanid);
00577
00578 if (!query.exec())
00579 MythContext::DBError("GetMplexID 4", query);
00580 else if (query.next())
00581 return query.value(0).toInt();
00582
00583 return 0;
00584 }
00585
00608
00609
00610 int ChannelUtil::GetBetterMplexID(int current_mplexid,
00611 int transport_id,
00612 int network_id)
00613 {
00614 VERBOSE(VB_SIPARSER,
00615 QString("GetBetterMplexID(mplexId %1, tId %2, netId %3)")
00616 .arg(current_mplexid).arg(transport_id).arg(network_id));
00617
00618 int q_networkid = 0, q_transportid = 0;
00619 MSqlQuery query(MSqlQuery::InitCon());
00620
00621 query.prepare(QString("SELECT networkid, transportid "
00622 "FROM dtv_multiplex "
00623 "WHERE mplexid = %1").arg(current_mplexid));
00624
00625 if (!query.exec() || !query.isActive())
00626 MythContext::DBError("Getting mplexid global search", query);
00627 else if (query.size())
00628 {
00629 query.next();
00630 q_networkid = query.value(0).toInt();
00631 q_transportid = query.value(1).toInt();
00632 }
00633
00634
00635 if ((q_networkid == network_id) && (q_transportid == transport_id))
00636 {
00637 VERBOSE(VB_SIPARSER,
00638 QString("GetBetterMplexID(): Returning perfect match %1")
00639 .arg(current_mplexid));
00640 return current_mplexid;
00641 }
00642
00643
00644 if (!q_networkid && !q_transportid)
00645 {
00646 int qsize = query.size();
00647 query.prepare(QString("UPDATE dtv_multiplex "
00648 "SET networkid = %1, transportid = %2 "
00649 "WHERE mplexid = %3")
00650 .arg(network_id).arg(transport_id).arg(current_mplexid));
00651
00652 if (!query.exec() || !query.isActive())
00653 MythContext::DBError("Getting mplexid global search", query);
00654
00655 VERBOSE(VB_SIPARSER, QString(
00656 "GetBetterMplexID(): net id and transport id "
00657 "are null, qsize(%1), Returning %2")
00658 .arg(qsize).arg(current_mplexid));
00659 return current_mplexid;
00660 }
00661
00662
00663 QString theQueries[2] =
00664 {
00665 QString("SELECT a.mplexid "
00666 "FROM dtv_multiplex a, dtv_multiplex b "
00667 "WHERE a.networkid = %1 AND "
00668 " a.transportid = %2 AND "
00669 " a.sourceid = b.sourceid AND "
00670 " b.mplexid = %3")
00671 .arg(network_id).arg(transport_id).arg(current_mplexid),
00672
00673 QString("SELECT mplexid "
00674 "FROM dtv_multiplex "
00675 "WHERE networkid = %1 AND "
00676 " transportid = %2")
00677 .arg(network_id).arg(transport_id),
00678 };
00679
00680 for (uint i=0; i<2; i++)
00681 {
00682 query.prepare(theQueries[i]);
00683
00684 if (!query.exec() || !query.isActive())
00685 MythContext::DBError("Finding matching mplexid", query);
00686
00687 if (query.size() == 1)
00688 {
00689 VERBOSE(VB_SIPARSER, QString(
00690 "GetBetterMplexID(): query#%1 qsize(%2) "
00691 "Returning %3")
00692 .arg(i).arg(query.size()).arg(current_mplexid));
00693 query.next();
00694 return query.value(0).toInt();
00695 }
00696
00697 if (query.size() > 1)
00698 {
00699 query.next();
00700 int ret = (i==0) ? current_mplexid : query.value(0).toInt();
00701 VERBOSE(VB_SIPARSER, QString(
00702 "GetBetterMplexID(): query#%1 qsize(%2) "
00703 "Returning %3")
00704 .arg(i).arg(query.size()).arg(ret));
00705 return ret;
00706 }
00707 }
00708
00709
00710 VERBOSE(VB_SIPARSER, QString("GetBetterMplexID(): Returning -1"));
00711 return -1;
00712 }
00713
00714 bool ChannelUtil::GetTuningParams(uint mplexid,
00715 QString &modulation,
00716 uint64_t &frequency,
00717 uint &dvb_transportid,
00718 uint &dvb_networkid,
00719 QString &si_std)
00720 {
00721 if (!mplexid || (mplexid == 32767))
00722 return false;
00723
00724 MSqlQuery query(MSqlQuery::InitCon());
00725 query.prepare(
00726 "SELECT transportid, networkid, frequency, modulation, sistandard "
00727 "FROM dtv_multiplex "
00728 "WHERE mplexid = :MPLEXID");
00729 query.bindValue(":MPLEXID", mplexid);
00730
00731 if (!query.exec() || !query.isActive())
00732 {
00733 MythContext::DBError("GetTuningParams failed ", query);
00734 return false;
00735 }
00736
00737 if (!query.next())
00738 return false;
00739
00740 dvb_transportid = query.value(0).toUInt();
00741 dvb_networkid = query.value(1).toUInt();
00742 frequency = (uint64_t) query.value(2).toDouble();
00743 modulation = query.value(3).toString();
00744 si_std = query.value(4).toString();
00745
00746 return true;
00747 }
00748
00749 QString ChannelUtil::GetChannelStringField(int chan_id, const QString &field)
00750 {
00751 if (chan_id < 0)
00752 return QString::null;
00753
00754 MSqlQuery query(MSqlQuery::InitCon());
00755 query.prepare(QString("SELECT %1 FROM channel "
00756 "WHERE chanid=%2").arg(field).arg(chan_id));
00757 if (!query.exec() || !query.isActive())
00758 {
00759 MythContext::DBError("Selecting channel/dtv_multiplex 1", query);
00760 return QString::null;
00761 }
00762 if (!query.size())
00763 return QString::null;
00764
00765 query.next();
00766 return query.value(0).toString();
00767 }
00768
00769 QString ChannelUtil::GetChanNum(int chan_id)
00770 {
00771 return GetChannelStringField(chan_id, QString("channum"));
00772 }
00773
00774 QString ChannelUtil::GetCallsign(int chan_id)
00775 {
00776 return GetChannelStringField(chan_id, QString("callsign"));
00777 }
00778
00779 QString ChannelUtil::GetServiceName(int chan_id)
00780 {
00781 return GetChannelStringField(chan_id, QString("name"));
00782 }
00783
00784 int ChannelUtil::GetSourceID(int db_mplexid)
00785 {
00786 MSqlQuery query(MSqlQuery::InitCon());
00787
00788 query.prepare(QString("SELECT sourceid "
00789 "FROM dtv_multiplex "
00790 "WHERE mplexid = %1").arg(db_mplexid));
00791
00792 if (!query.exec() || !query.isActive())
00793 {
00794 MythContext::DBError("Selecting channel/dtv_multiplex", query);
00795 return -1;
00796 }
00797
00798 if (query.size() > 0)
00799 {
00800 query.next();
00801 return query.value(0).toInt();
00802 }
00803 return -1;
00804 }
00805
00806 uint ChannelUtil::GetSourceIDForChannel(uint chanid)
00807 {
00808 MSqlQuery query(MSqlQuery::InitCon());
00809
00810 query.prepare(
00811 "SELECT sourceid "
00812 "FROM channel "
00813 "WHERE chanid = :CHANID");
00814 query.bindValue(":CHANID", chanid);
00815
00816 if (!query.exec())
00817 MythContext::DBError("Selecting channel/dtv_multiplex", query);
00818 else if (query.next())
00819 return query.value(0).toUInt();
00820
00821 return 0;
00822 }
00823
00824 int ChannelUtil::GetInputID(int source_id, int card_id)
00825 {
00826 int input_id = -1;
00827
00828 MSqlQuery query(MSqlQuery::InitCon());
00829 query.prepare("SELECT cardinputid"
00830 " FROM cardinput"
00831 " WHERE sourceid = :SOURCEID"
00832 " AND cardid = :CARDID");
00833 query.bindValue(":SOURCEID", source_id);
00834 query.bindValue(":CARDID", card_id);
00835
00836 if (query.exec() && query.isActive() && query.next())
00837 input_id = query.value(0).toInt();
00838
00839 return input_id;
00840 }
00841
00842 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
00843 uint cardid,
00844 const QString &input,
00845 const QString &channum)
00846 {
00847 QString retval = QString::null;
00848
00849 MSqlQuery query(MSqlQuery::InitCon());
00850
00851 query.prepare(
00852 QString(
00853 "SELECT channel.%1 "
00854 "FROM channel, capturecard, cardinput "
00855 "WHERE channel.channum = :CHANNUM AND "
00856 " channel.sourceid = cardinput.sourceid AND "
00857 " cardinput.inputname = :INPUT AND "
00858 " cardinput.cardid = capturecard.cardid AND "
00859 " capturecard.cardid = :CARDID ")
00860 .arg(channel_field));
00861
00862 query.bindValue(":CARDID", cardid);
00863 query.bindValue(":INPUT", input);
00864 query.bindValue(":CHANNUM", channum);
00865
00866 if (!query.exec() || !query.isActive())
00867 MythContext::DBError("getchannelvalue", query);
00868 else if (query.next())
00869 retval = query.value(0).toString();
00870
00871 return retval;
00872 }
00873
00874 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
00875 uint sourceid,
00876 const QString &channum)
00877 {
00878 QString retval = QString::null;
00879
00880 MSqlQuery query(MSqlQuery::InitCon());
00881
00882 query.prepare(
00883 QString(
00884 "SELECT channel.%1 "
00885 "FROM channel "
00886 "WHERE channum = :CHANNUM AND "
00887 " sourceid = :SOURCEID")
00888 .arg(channel_field));
00889
00890 query.bindValue(":SOURCEID", sourceid);
00891 query.bindValue(":CHANNUM", channum);
00892
00893 if (!query.exec() || !query.isActive())
00894 MythContext::DBError("getchannelvalue", query);
00895 else if (query.next())
00896 retval = query.value(0).toString();
00897
00898 return retval;
00899 }
00900
00901 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
00902 uint cardid,
00903 const QString &input,
00904 const QString &channum)
00905 {
00906 QString val = GetChannelValueStr(channel_field, cardid, input, channum);
00907
00908 int retval = 0;
00909 if (!val.isEmpty())
00910 retval = val.toInt();
00911
00912 return (retval) ? retval : -1;
00913 }
00914
00915 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
00916 uint sourceid,
00917 const QString &channum)
00918 {
00919 QString val = GetChannelValueStr(channel_field, sourceid, channum);
00920
00921 int retval = 0;
00922 if (!val.isEmpty())
00923 retval = val.toInt();
00924
00925 return (retval) ? retval : -1;
00926 }
00927
00928 bool ChannelUtil::IsOnSameMultiplex(uint srcid,
00929 const QString &new_channum,
00930 const QString &old_channum)
00931 {
00932 if (new_channum.isEmpty() || old_channum.isEmpty())
00933 return false;
00934
00935 if (new_channum == old_channum)
00936 return true;
00937
00938 uint old_mplexid = GetMplexID(srcid, old_channum);
00939 if (!old_mplexid)
00940 return false;
00941
00942 uint new_mplexid = GetMplexID(srcid, new_channum);
00943 if (!new_mplexid)
00944 return false;
00945
00946 VERBOSE(VB_CHANNEL, QString("IsOnSameMultiplex? %1==%2 -> %3")
00947 .arg(old_mplexid).arg(new_mplexid)
00948 .arg(old_mplexid == new_mplexid));
00949
00950 return old_mplexid == new_mplexid;
00951 }
00952
00953 bool ChannelUtil::SetChannelValue(const QString &field_name,
00954 QString value,
00955 uint sourceid,
00956 const QString &channum)
00957 {
00958 MSqlQuery query(MSqlQuery::InitCon());
00959
00960 query.prepare(
00961 QString("UPDATE channel SET channel.%1=:VALUE "
00962 "WHERE channel.channum = :CHANNUM AND "
00963 " channel.sourceid = :SOURCEID").arg(field_name));
00964
00965 query.bindValue(":VALUE", value);
00966 query.bindValue(":CHANNUM", channum);
00967 query.bindValue(":SOURCEID", sourceid);
00968
00969 return query.exec();
00970 }
00971
00972 QString ChannelUtil::GetUnknownCallsign(void)
00973 {
00974 return QDeepCopy<QString>(QObject::tr("UNKNOWN", "Synthesized callsign"));
00975 }
00976
00977 int ChannelUtil::GetChanID(int mplexid, int service_transport_id,
00978 int major_channel, int minor_channel,
00979 int program_number)
00980 {
00981 MSqlQuery query(MSqlQuery::InitCon());
00982
00983
00984 query.prepare("SELECT sourceid "
00985 "FROM dtv_multiplex "
00986 "WHERE mplexid = :MPLEXID");
00987 query.bindValue(":MPLEXID", mplexid);
00988 if (!query.exec())
00989 {
00990 MythContext::DBError("Selecting channel/dtv_multiplex 2", query);
00991 return -1;
00992 }
00993 if (!query.next())
00994 return -1;
00995
00996 int source_id = query.value(0).toInt();
00997
00998 QStringList qstr;
00999
01000
01001 qstr.push_back(
01002 QString("SELECT chanid FROM channel,dtv_multiplex "
01003 "WHERE channel.sourceid = %1 AND "
01004 " atsc_major_chan = %2 AND "
01005 " atsc_minor_chan = %3 AND "
01006 " dtv_multiplex.transportid = %4 AND "
01007 " dtv_multiplex.mplexid = %5 AND "
01008 " dtv_multiplex.sourceid = channel.sourceid AND "
01009 " dtv_multiplex.mplexid = channel.mplexid")
01010 .arg(source_id).arg(major_channel).arg(minor_channel)
01011 .arg(service_transport_id).arg(mplexid));
01012
01013
01014
01015 qstr.push_back(
01016 QString("SELECT chanid FROM channel "
01017 "WHERE sourceid=%1 AND "
01018 "atsc_major_chan=%2 AND "
01019 "atsc_minor_chan=%3")
01020 .arg(source_id).arg(major_channel).arg(minor_channel));
01021
01022
01023 qstr.push_back(
01024 QString("SELECT chanid FROM channel "
01025 "WHERE sourceid=%1 AND serviceID=%1 AND mplexid=%2")
01026 .arg(source_id).arg(program_number).arg(mplexid));
01027
01028 for (uint i = 0; i < qstr.size(); i++)
01029 {
01030 query.prepare(qstr[i]);
01031 if (!query.exec())
01032 MythContext::DBError("Selecting channel/dtv_multiplex 3", query);
01033 else if (query.next())
01034 return query.value(0).toInt();
01035 }
01036
01037 return -1;
01038 }
01039
01040 uint ChannelUtil::FindChannel(uint sourceid, const QString &freqid)
01041 {
01042 MSqlQuery query(MSqlQuery::InitCon());
01043 query.prepare("SELECT chanid "
01044 "FROM channel "
01045 "WHERE sourceid = :SOURCEID AND "
01046 " freqid = :FREQID");
01047
01048 query.bindValue(":SOURCEID", sourceid);
01049 query.bindValue(":FREQID", freqid);
01050
01051 if (!query.exec() || !query.isActive())
01052 MythContext::DBError("FindChannel", query);
01053 else if (query.next())
01054 return query.value(0).toUInt();
01055
01056 return 0;
01057 }
01058
01059
01060 static uint get_max_chanid(uint sourceid)
01061 {
01062 QString qstr = "SELECT MAX(chanid) FROM channel ";
01063 qstr += (sourceid) ? "WHERE sourceid = :SOURCEID" : "";
01064
01065 MSqlQuery query(MSqlQuery::DDCon());
01066 query.prepare(qstr);
01067
01068 if (sourceid)
01069 query.bindValue(":SOURCEID", sourceid);
01070
01071 if (!query.exec() || !query.isActive())
01072 MythContext::DBError("Getting chanid for new channel (2)", query);
01073 else if (!query.next())
01074 VERBOSE(VB_IMPORTANT, "Error getting chanid for new channel.");
01075 else
01076 return query.value(0).toUInt();
01077
01078 return 0;
01079 }
01080
01081 static bool chanid_available(uint chanid)
01082 {
01083 MSqlQuery query(MSqlQuery::DDCon());
01084 query.prepare(
01085 "SELECT chanid "
01086 "FROM channel "
01087 "WHERE chanid = :CHANID");
01088 query.bindValue(":CHANID", chanid);
01089
01090 if (!query.exec() || !query.isActive())
01091 MythContext::DBError("is_chan_id_available", query);
01092 else if (query.size() == 0)
01093 return true;
01094
01095 return false;
01096 }
01097
01102 int ChannelUtil::CreateChanID(uint sourceid, const QString &chan_num)
01103 {
01104
01105 uint chanid = 0;
01106 int chansep = chan_num.find(QRegExp("\\D"));
01107 if (chansep > 0)
01108 {
01109 chanid =
01110 sourceid * 1000 +
01111 chan_num.left(chansep).toInt() * 10 +
01112 chan_num.right(chan_num.length()-chansep-1).toInt();
01113 }
01114 else
01115 {
01116 chanid = sourceid * 1000 + chan_num.toInt();
01117 }
01118
01119 if ((chanid > sourceid * 1000) && (chanid_available(chanid)))
01120 return chanid;
01121
01122
01123 chanid = max(get_max_chanid(sourceid) + 1, sourceid * 1000);
01124
01125 if (chanid_available(chanid))
01126 return chanid;
01127
01128
01129 chanid = get_max_chanid(0) + 1;
01130
01131 if (chanid_available(chanid))
01132 return chanid;
01133
01134
01135 return -1;
01136 }
01137
01138 bool ChannelUtil::CreateChannel(uint db_mplexid,
01139 uint db_sourceid,
01140 uint new_channel_id,
01141 const QString &callsign,
01142 const QString &service_name,
01143 const QString &chan_num,
01144 uint service_id,
01145 uint atsc_major_channel,
01146 uint atsc_minor_channel,
01147 bool use_on_air_guide,
01148 bool hidden,
01149 bool hidden_in_guide,
01150 const QString &freqid,
01151 QString icon,
01152 QString format,
01153 QString xmltvid,
01154 QString default_authority)
01155 {
01156 MSqlQuery query(MSqlQuery::InitCon());
01157
01158 QString chanNum = (chan_num == "-1") ?
01159 QString::number(service_id) : chan_num;
01160
01161 query.prepare(
01162 "INSERT INTO channel "
01163 " (chanid, channum, sourceid, callsign, "
01164 " name, mplexid, serviceid, "
01165 " atsc_major_chan, atsc_minor_chan, "
01166 " useonairguide, visible, freqid, tvformat, "
01167 " icon, xmltvid, default_authority) "
01168 "VALUES "
01169 " (:CHANID, :CHANNUM, :SOURCEID, :CALLSIGN, "
01170 " :NAME, :MPLEXID, :SERVICEID, "
01171 " :MAJORCHAN, :MINORCHAN, "
01172 " :USEOAG, :VISIBLE, :FREQID, :TVFORMAT, "
01173 " :ICON, :XMLTVID, :AUTHORITY)");
01174
01175 query.bindValue(":CHANID", new_channel_id);
01176 query.bindValue(":CHANNUM", chanNum);
01177 query.bindValue(":SOURCEID", db_sourceid);
01178 query.bindValue(":CALLSIGN", callsign.utf8());
01179 query.bindValue(":NAME", service_name.utf8());
01180
01181 if (db_mplexid > 0)
01182 query.bindValue(":MPLEXID", db_mplexid);
01183
01184 query.bindValue(":SERVICEID", service_id);
01185 query.bindValue(":MAJORCHAN", atsc_major_channel);
01186 query.bindValue(":MINORCHAN", atsc_minor_channel);
01187 query.bindValue(":USEOAG", use_on_air_guide);
01188 query.bindValue(":VISIBLE", !hidden);
01189 (void) hidden_in_guide;
01190
01191 if (!freqid.isEmpty())
01192 query.bindValue(":FREQID", freqid);
01193
01194 QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : format;
01195 query.bindValue(":TVFORMAT", tvformat);
01196
01197 icon = (icon.isEmpty()) ? "" : icon;
01198 query.bindValue(":ICON", icon);
01199
01200 xmltvid = (xmltvid.isEmpty()) ? "" : xmltvid;
01201 query.bindValue(":XMLTVID", xmltvid);
01202
01203 default_authority = (default_authority.isEmpty()) ? "" : default_authority;
01204 query.bindValue(":AUTHORITY", default_authority);
01205
01206 if (!query.exec() || !query.isActive())
01207 {
01208 MythContext::DBError("Adding Service", query);
01209 return false;
01210 }
01211 return true;
01212 }
01213
01214 bool ChannelUtil::UpdateChannel(uint db_mplexid,
01215 uint source_id,
01216 uint channel_id,
01217 const QString &callsign,
01218 const QString &service_name,
01219 const QString &chan_num,
01220 uint service_id,
01221 uint atsc_major_channel,
01222 uint atsc_minor_channel,
01223 bool use_on_air_guide,
01224 bool hidden,
01225 bool hidden_in_guide,
01226 QString freqid,
01227 QString icon,
01228 QString format,
01229 QString xmltvid,
01230 QString default_authority)
01231 {
01232 if (!channel_id)
01233 return false;
01234
01235 QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : format;
01236 bool set_channum = !chan_num.isEmpty() && chan_num != "-1";
01237 QString qstr = QString(
01238 "UPDATE channel "
01239 "SET %1 %2 %3 %4 %5 %6"
01240 " mplexid = :MPLEXID, serviceid = :SERVICEID, "
01241 " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
01242 " callsign = :CALLSIGN, name = :NAME, "
01243 " sourceid = :SOURCEID, useonairguide = :USEOAG, "
01244 " visible = :VISIBLE "
01245 "WHERE chanid=:CHANID")
01246 .arg((!set_channum) ? "" : "channum = :CHANNUM, ")
01247 .arg((freqid.isEmpty()) ? "" : "freqid = :FREQID, ")
01248 .arg((icon.isEmpty()) ? "" : "icon = :ICON, ")
01249 .arg((tvformat.isEmpty()) ? "" : "tvformat = :TVFORMAT, ")
01250 .arg((xmltvid.isEmpty()) ? "" : "xmltvid = :XMLTVID, ")
01251 .arg((default_authority.isEmpty()) ?
01252 "" : "default_authority = :AUTHORITY,");
01253
01254 MSqlQuery query(MSqlQuery::InitCon());
01255 query.prepare(qstr);
01256
01257 query.bindValue(":CHANID", channel_id);
01258
01259 if (set_channum)
01260 query.bindValue(":CHANNUM", chan_num.utf8());
01261
01262 query.bindValue(":SOURCEID", source_id);
01263 query.bindValue(":CALLSIGN", callsign.utf8());
01264 query.bindValue(":NAME", service_name.utf8());
01265
01266 query.bindValue(":MPLEXID", db_mplexid);
01267
01268 query.bindValue(":SERVICEID", service_id);
01269 query.bindValue(":MAJORCHAN", atsc_major_channel);
01270 query.bindValue(":MINORCHAN", atsc_minor_channel);
01271 query.bindValue(":USEOAG", use_on_air_guide);
01272 query.bindValue(":VISIBLE", !hidden);
01273 (void) hidden_in_guide;
01274
01275 if (!freqid.isEmpty())
01276 query.bindValue(":FREQID", freqid);
01277
01278 if (!tvformat.isEmpty())
01279 query.bindValue(":TVFORMAT", tvformat);
01280
01281 if (!icon.isEmpty())
01282 query.bindValue(":ICON", icon);
01283 if (!xmltvid.isEmpty())
01284 query.bindValue(":XMLTVID", xmltvid);
01285 if (!default_authority.isEmpty())
01286 query.bindValue(":AUTHORITY", default_authority);
01287
01288 if (!query.exec())
01289 {
01290 MythContext::DBError("Updating Service", query);
01291 return false;
01292 }
01293 return true;
01294 }
01295
01296 bool ChannelUtil::SetServiceVersion(int mplexid, int version)
01297 {
01298 MSqlQuery query(MSqlQuery::InitCon());
01299
01300 query.prepare(
01301 QString("UPDATE dtv_multiplex "
01302 "SET serviceversion = %1 "
01303 "WHERE mplexid = %2").arg(version).arg(mplexid));
01304
01305 if (!query.exec() || !query.isActive())
01306 {
01307 MythContext::DBError("Selecting channel/dtv_multiplex", query);
01308 return false;
01309 }
01310 return true;
01311 }
01312
01313 int ChannelUtil::GetServiceVersion(int mplexid)
01314 {
01315 MSqlQuery query(MSqlQuery::InitCon());
01316
01317 query.prepare(QString("SELECT serviceversion "
01318 "FROM dtv_multiplex "
01319 "WHERE mplexid = %1").arg(mplexid));
01320
01321 if (!query.exec() || !query.isActive())
01322 {
01323 MythContext::DBError("Selecting channel/dtv_multiplex", query);
01324 return false;
01325 }
01326
01327 if (query.size() > 0)
01328 {
01329 query.next();
01330 return query.value(0).toInt();
01331 }
01332 return -1;
01333 }
01334
01335 bool ChannelUtil::GetATSCChannel(uint sourceid, const QString &channum,
01336 uint &major, uint &minor)
01337 {
01338 major = minor = 0;
01339
01340 MSqlQuery query(MSqlQuery::InitCon());
01341 query.prepare(
01342 "SELECT atsc_major_chan, atsc_minor_chan "
01343 "FROM channel "
01344 "WHERE channum = :CHANNUM AND "
01345 " sourceid = :SOURCEID");
01346
01347 query.bindValue(":SOURCEID", sourceid);
01348 query.bindValue(":CHANNUM", channum);
01349
01350 if (!query.exec() || !query.isActive())
01351 MythContext::DBError("getatscchannel", query);
01352 else if (query.next())
01353 {
01354 major = query.value(0).toUInt();
01355 minor = query.value(1).toUInt();
01356 return true;
01357 }
01358
01359 return false;
01360 }
01361
01362 bool ChannelUtil::GetChannelData(
01363 uint sourceid, const QString &channum,
01364 QString &tvformat, QString &modulation,
01365 QString &freqtable, QString &freqid,
01366 int &finetune, uint64_t &frequency,
01367 QString &dtv_si_std, int &mpeg_prog_num,
01368 uint &atsc_major, uint &atsc_minor,
01369 uint &dvb_transportid, uint &dvb_networkid,
01370 uint &mplexid,
01371 bool &commfree)
01372 {
01373 tvformat = modulation = freqtable = QString::null;
01374 freqid = dtv_si_std = QString::null;
01375 finetune = 0;
01376 frequency = 0;
01377 mpeg_prog_num = -1;
01378 atsc_major = atsc_minor = mplexid = 0;
01379 dvb_networkid = dvb_transportid = 0;
01380 commfree = false;
01381
01382 MSqlQuery query(MSqlQuery::InitCon());
01383 query.prepare(
01384 "SELECT finetune, freqid, tvformat, freqtable, "
01385 " commmethod, mplexid, "
01386 " atsc_major_chan, atsc_minor_chan, serviceid "
01387 "FROM channel, videosource "
01388 "WHERE videosource.sourceid = channel.sourceid AND "
01389 " channum = :CHANNUM AND "
01390 " channel.sourceid = :SOURCEID");
01391 query.bindValue(":CHANNUM", channum);
01392 query.bindValue(":SOURCEID", sourceid);
01393
01394 if (!query.exec() || !query.isActive())
01395 {
01396 MythContext::DBError("GetChannelData", query);
01397 return false;
01398 }
01399 else if (!query.next())
01400 {
01401 VERBOSE(VB_IMPORTANT, QString(
01402 "GetChannelData() failed because it could not\n"
01403 "\t\t\tfind channel number '%1' in DB for source '%2'.")
01404 .arg(channum).arg(sourceid));
01405 return false;
01406 }
01407
01408 finetune = query.value(0).toInt();
01409 freqid = query.value(1).toString();
01410 tvformat = query.value(2).toString();
01411 freqtable = query.value(3).toString();
01412 commfree = (query.value(4).toInt() == -2);
01413 mplexid = query.value(5).toUInt();
01414 atsc_major = query.value(6).toUInt();
01415 atsc_minor = query.value(7).toUInt();
01416 mpeg_prog_num = query.value(8).toUInt();
01417
01418 if (!mplexid || (mplexid == 32767))
01419 return true;
01420
01421 return GetTuningParams(mplexid, modulation, frequency,
01422 dvb_transportid, dvb_networkid, dtv_si_std);
01423 }
01424
01425 bool ChannelUtil::GetChannelSettings(int chanid, bool &useonairguide,
01426 bool &hidden)
01427 {
01428 useonairguide = true;
01429 hidden = false;
01430
01431 MSqlQuery query(MSqlQuery::InitCon());
01432 query.prepare(
01433 "SELECT useonairguide, visible "
01434 "FROM channel "
01435 "WHERE chanid = :CHANID");
01436 query.bindValue(":CHANID", chanid);
01437
01438 if (!query.exec() || !query.isActive())
01439 {
01440 MythContext::DBError("GetChannelSettings", query);
01441 return false;
01442 }
01443 else if (!query.next())
01444 {
01445 VERBOSE(VB_IMPORTANT, QString(
01446 "GetChannelSettings() failed because it could not "
01447 "find channel id '%1'.").arg(chanid));
01448 return false;
01449 }
01450
01451 useonairguide = (query.value(0).toInt() > 0);
01452 hidden = (query.value(1).toInt() == 0);
01453
01454 return true;
01455 }
01456
01457 DBChanList ChannelUtil::GetChannels(uint sourceid, bool vis_only, QString grp)
01458 {
01459 DBChanList list;
01460 QMap<uint,uint> favorites;
01461 MSqlQuery query(MSqlQuery::InitCon());
01462 query.prepare(
01463 "SELECT chanid, favid "
01464 "FROM favorites");
01465 if (!query.exec() || !query.isActive())
01466 MythContext::DBError("get channels -- favorites", query);
01467 else
01468 {
01469 while (query.next())
01470 favorites[query.value(0).toUInt()] = query.value(1).toUInt();
01471 }
01472
01473 QString qstr =
01474 "SELECT channum, callsign, chanid, "
01475 " atsc_major_chan, atsc_minor_chan, "
01476 " name, icon, mplexid, visible "
01477 "FROM channel ";
01478
01479 if (sourceid)
01480 qstr += QString("WHERE sourceid='%1' ").arg(sourceid);
01481 else
01482 qstr += ",cardinput,capturecard "
01483 "WHERE cardinput.sourceid = channel.sourceid AND "
01484 " cardinput.cardid = capturecard.cardid ";
01485
01486 if (vis_only)
01487 qstr += "AND visible=1 ";
01488
01489 if (!grp.isEmpty())
01490 qstr += QString("GROUP BY %1 ").arg(grp);
01491
01492 query.prepare(qstr);
01493 if (!query.exec() || !query.isActive())
01494 {
01495 MythContext::DBError("get channels -- sourceid", query);
01496 return list;
01497 }
01498
01499 while (query.next())
01500 {
01501 if (query.value(0).toString().isEmpty() || !query.value(2).toUInt())
01502 continue;
01503
01504 DBChannel chan(
01505 query.value(0).toString(),
01506 QString::fromUtf8(query.value(1).toString()),
01507 query.value(2).toUInt(),
01508 query.value(3).toUInt(),
01509 query.value(4).toUInt(),
01510 favorites[query.value(2).toUInt()],
01511 query.value(7).toUInt(),
01512 query.value(8).toBool(),
01513 QString::fromUtf8(query.value(5).toString()),
01514 query.value(6).toString());
01515
01516 list.push_back(chan);
01517 }
01518
01519 return list;
01520 }
01521
01522 inline bool lt_callsign(const DBChannel &a, const DBChannel &b)
01523 {
01524 return QString::localeAwareCompare(a.callsign, b.callsign) < 0;
01525 }
01526
01527 static QMutex sepExprLock;
01528 static const QRegExp sepExpr("(_|-|#|\\.)");
01529
01530 inline bool lt_smart(const DBChannel &a, const DBChannel &b)
01531 {
01532 int cmp = 0;
01533
01534 bool isIntA, isIntB;
01535 int a_int = a.channum.toUInt(&isIntA);
01536 int b_int = b.channum.toUInt(&isIntB);
01537 int a_major = a.major_chan;
01538 int b_major = b.major_chan;
01539 int a_minor = a.minor_chan;
01540 int b_minor = b.minor_chan;
01541
01542
01543 bool tmp1, tmp2;
01544 int idxA, idxB;
01545 {
01546 QMutexLocker locker(&sepExprLock);
01547 idxA = a.channum.find(sepExpr);
01548 idxB = b.channum.find(sepExpr);
01549 }
01550 if (idxA >= 0)
01551 {
01552 int major = a.channum.left(idxA).toUInt(&tmp1);
01553 int minor = a.channum.mid(idxA+1).toUInt(&tmp2);
01554 if (tmp1 && tmp2)
01555 (a_major = major), (a_minor = minor), (isIntA = false);
01556 }
01557
01558 if (idxB >= 0)
01559 {
01560 int major = b.channum.left(idxB).toUInt(&tmp1);
01561 int minor = b.channum.mid(idxB+1).toUInt(&tmp2);
01562 if (tmp1 && tmp2)
01563 (b_major = major), (b_minor = minor), (isIntB = false);
01564 }
01565
01566
01567 if ((a_minor > 0) && isIntA)
01568 {
01569 int atsc_int = (QString("%1%2").arg(a_major).arg(a_minor)).toInt();
01570 a_minor = (atsc_int == a_int) ? a_minor : 0;
01571 }
01572
01573 if ((b_minor > 0) && isIntB)
01574 {
01575 int atsc_int = (QString("%1%2").arg(b_major).arg(b_minor)).toInt();
01576 b_minor = (atsc_int == b_int) ? b_minor : 0;
01577 }
01578
01579
01580
01581 if ((a_minor || b_minor) &&
01582 (a_minor || isIntA) && (b_minor || isIntB))
01583 {
01584 int a_maj = (!a_minor && isIntA) ? a_int : a_major;
01585 int b_maj = (!b_minor && isIntB) ? b_int : b_major;
01586 if ((cmp = a_maj - b_maj))
01587 return cmp < 0;
01588
01589 if ((cmp = a_minor - b_minor))
01590 return cmp < 0;
01591 }
01592
01593 if (isIntA && isIntB)
01594 {
01595
01596 cmp = a_int - b_int;
01597 if (cmp)
01598 return cmp < 0;
01599 }
01600 else if (isIntA ^ isIntB)
01601 {
01602
01603 return isIntA;
01604 }
01605 else
01606 {
01607
01608 cmp = QString::localeAwareCompare(a.channum, b.channum);
01609 if (cmp)
01610 return cmp < 0;
01611 }
01612
01613 return lt_callsign(a,b);
01614 }
01615
01616 void ChannelUtil::SortChannels(DBChanList &list, const QString &order,
01617 bool eliminate_duplicates)
01618 {
01619 bool cs = order.lower() == "callsign";
01620 if (cs)
01621 stable_sort(list.begin(), list.end(), lt_callsign);
01622 else
01623 stable_sort(list.begin(), list.end(), lt_smart);
01624
01625 if (eliminate_duplicates && !list.empty())
01626 {
01627 DBChanList tmp;
01628 tmp.push_back(list[0]);
01629 for (uint i = 1; i < list.size(); i++)
01630 {
01631 if ((cs && lt_callsign(tmp.back(), list[i])) ||
01632 (!cs && lt_smart(tmp.back(), list[i])))
01633 {
01634 tmp.push_back(list[i]);
01635 }
01636 }
01637
01638 list = tmp;
01639 }
01640 }
01641
01642 void ChannelUtil::EliminateDuplicateChanNum(DBChanList &list)
01643 {
01644 typedef std::set<QString> seen_set;
01645 seen_set seen;
01646
01647 DBChanList::iterator it = list.begin();
01648
01649 while (it != list.end())
01650 {
01651 QString tmp = QDeepCopy<QString>(it->channum);
01652 std::pair<seen_set::iterator, bool> insret = seen.insert(tmp);
01653 if (insret.second)
01654 ++it;
01655 else
01656 it = list.erase(it);
01657 }
01658 }
01659
01660 uint ChannelUtil::GetNextChannel(
01661 const DBChanList &sorted,
01662 uint old_chanid,
01663 uint mplexid_restriction,
01664 int direction)
01665 {
01666 DBChanList::const_iterator it =
01667 find(sorted.begin(), sorted.end(), old_chanid);
01668
01669 if (it == sorted.end())
01670 it = sorted.begin();
01671
01672 if (it == sorted.end())
01673 return 0;
01674
01675 DBChanList::const_iterator start = it;
01676 bool skip_non_visible = true;
01677
01678 if (CHANNEL_DIRECTION_DOWN == direction)
01679 {
01680 do
01681 {
01682 if (it == sorted.begin())
01683 it = find(sorted.begin(), sorted.end(),
01684 sorted.rbegin()->chanid);
01685 else
01686 it--;
01687 }
01688 while ((it != start) &&
01689 ((skip_non_visible && !it->visible) ||
01690 (mplexid_restriction &&
01691 (mplexid_restriction != it->mplexid))));
01692 }
01693 else if (CHANNEL_DIRECTION_UP == direction)
01694 {
01695 do
01696 {
01697 it++;
01698 if (it == sorted.end())
01699 it = sorted.begin();
01700 }
01701 while ((it != start) &&
01702 ((skip_non_visible && !it->visible) ||
01703 (mplexid_restriction &&
01704 (mplexid_restriction != it->mplexid))));
01705 }
01706 else if (CHANNEL_DIRECTION_FAVORITE == direction)
01707 {
01708 do
01709 {
01710 it++;
01711 if (it == sorted.end())
01712 it = sorted.begin();
01713 }
01714 while ((it != start) &&
01715 (!it->favorite ||
01716 (skip_non_visible && !it->visible) ||
01717 (mplexid_restriction &&
01718 (mplexid_restriction != it->mplexid))));
01719 }
01720
01721 return it->chanid;
01722 }
01723
01724