void TVBrowseHelper::GetNextProgramDB( BrowseDirection direction, InfoMap &infoMap) const { uint chanid = infoMap["chanid"].toUInt(); if (!chanid) { LOG(VB_GENERAL, LOG_ERR, LOC + "GetNextProgramDB() requires a chanid"); return; } int chandir = -1; switch (direction) { case BROWSE_UP: chandir = CHANNEL_DIRECTION_UP; break; case BROWSE_DOWN: chandir = CHANNEL_DIRECTION_DOWN; break; case BROWSE_FAVORITE: chandir = CHANNEL_DIRECTION_FAVORITE; break; } if (chandir != -1) { chanid = ChannelUtil::GetNextChannel( db_all_visible_channels, chanid, 0 /*mplexid_restriction*/, chandir, true /*skip non visible*/, true /*skip same callsign*/); } infoMap["chanid"] = QString::number(chanid); infoMap["channum"] = db_chanid_to_channum[chanid]; QDateTime nowtime = QDateTime::currentDateTime(); QDateTime latesttime = nowtime.addSecs(6*60*60); QDateTime browsetime = QDateTime::fromString( infoMap["dbstarttime"], Qt::ISODate); MSqlBindings bindings; bindings[":CHANID"] = chanid; bindings[":NOWTS"] = nowtime; bindings[":LATESTTS"] = latesttime; bindings[":BROWSETS"] = browsetime; bindings[":BROWSETS2"] = browsetime; QString querystr = " WHERE program.chanid = :CHANID "; switch (direction) { case BROWSE_LEFT: querystr += " AND program.endtime <= :BROWSETS " " AND program.endtime > :NOWTS "; break; case BROWSE_RIGHT: querystr += " AND program.starttime > :BROWSETS " " AND program.starttime < :LATESTTS "; break; default: querystr += " AND program.starttime <= :BROWSETS " " AND program.endtime > :BROWSETS2 "; }; ProgramList progList; ProgramList dummySched; LoadFromProgram(progList, querystr, bindings, dummySched); if (progList.empty()) { infoMap["dbstarttime"] = ""; return; } const ProgramInfo *prog = (direction == BROWSE_LEFT) ? progList[progList.size() - 1] : progList[0]; infoMap["dbstarttime"] = prog->GetScheduledStartTime(ISODate); }
void MIDIInstrumentParameterPanel::slotSelectBank(int index) { RG_DEBUG << "slotSelectBank() begin..."; if (!getSelectedInstrument()) return; MidiDevice *md = dynamic_cast<MidiDevice *>(getSelectedInstrument()->getDevice()); if (!md) { std::cerr << "WARNING: MIDIInstrumentParameterPanel::slotSelectBank(): No MidiDevice for Instrument " << getSelectedInstrument()->getId() << '\n'; return; } const MidiBank &bank = m_banks[index]; bool change = false; if (md->getVariationType() != MidiDevice::VariationFromLSB) { if (getSelectedInstrument()->getLSB() != bank.getLSB()) { getSelectedInstrument()->setLSB(bank.getLSB()); change = true; } } if (md->getVariationType() != MidiDevice::VariationFromMSB) { if (getSelectedInstrument()->getMSB() != bank.getMSB()) { getSelectedInstrument()->setMSB(bank.getMSB()); change = true; } } // If no change, bail. if (!change) return; // Make sure the Instrument is valid WRT the Device. // If the current bank/program is not valid for this device, fix it. if (!getSelectedInstrument()->isProgramValid()) { // If we're not in variations mode... if (md->getVariationType() == MidiDevice::NoVariations) { // ...go with the first program ProgramList programList = md->getPrograms(bank); if (!programList.empty()) { // Switch to the first program in this bank. getSelectedInstrument()->setProgram(programList.front()); } else { // No programs for this bank. Just go with 0. getSelectedInstrument()->setProgramChange(0); } } else { // We're in variations mode... // This is the three-comboboxes (bank/program/variation) case. // It's an extremely difficult case to handle, so we're just // going to punt and give them the first program/variation in // the bank they just selected. // Get the variation bank list for this bank BankList bankList; if (md->getVariationType() == MidiDevice::VariationFromMSB) { bankList = md->getBanksByLSB( getSelectedInstrument()->isPercussion(), bank.getLSB()); } else { bankList = md->getBanksByMSB( getSelectedInstrument()->isPercussion(), bank.getMSB()); } if (!bankList.empty()) { // Pick the first bank MidiBank firstBank = bankList.front(); // Get the program list ProgramList programList = md->getPrograms(firstBank); if (!programList.empty()) { // Pick the first program getSelectedInstrument()->setProgram(programList.front()); } } // To make the above more complex, we could consider the // case where the Program Change happens to be valid for // some variation bank in the newly selected bank. Then // go with the 0th variation bank that has that program // change. But I think this is complicated enough. } } getSelectedInstrument()->sendChannelSetup(); // This is why changed() isn't called within // the setters. If it were, then each of the above changes would // result in a change notification going out. Worst case, that // would be three change notifications and the first two would be // sent when the Instrument was in an inconsistent state. // Rule: Avoid sending change notifications from setters. // Why? It reduces the number of notifications which improves // performance. It avoids sending notifications when an object's // state is inconsistent. It avoids endless loops. getSelectedInstrument()->changed(); }
/** \brief Fills RecordingInfo for the program that airs at * "desiredts" on "chanid". * \param chanid %Channel ID on which to search for program. * \param desiredts Date and Time for which we desire the program. * \param genUnknown Generate a full entry for live-tv if unknown * \param maxHours Clamp the maximum time to X hours from dtime. * \return LoadStatus describing what happened. */ RecordingInfo::RecordingInfo( uint _chanid, const QDateTime &desiredts, bool genUnknown, uint maxHours, LoadStatus *status) : oldrecstatus(rsUnknown), savedrecstatus(rsUnknown), future(false), schedorder(0), mplexid(0), desiredrecstartts(), desiredrecendts(), record(NULL) { ProgramList schedList; ProgramList progList; MSqlBindings bindings; QString querystr = "WHERE program.chanid = :CHANID AND " " program.starttime < :STARTTS1 AND " " program.endtime > :STARTTS2 "; bindings[":CHANID"] = QString::number(_chanid); QDateTime query_startts = desiredts.addSecs(50 - desiredts.time().second()); bindings[":STARTTS1"] = query_startts; bindings[":STARTTS2"] = query_startts; ::LoadFromScheduler(schedList); LoadFromProgram(progList, querystr, bindings, schedList); if (!progList.empty()) { ProgramInfo *pginfo = progList[0]; if (maxHours > 0) { if (desiredts.secsTo( pginfo->GetScheduledEndTime()) > (int)maxHours * 3600) { pginfo->SetScheduledEndTime(desiredts.addSecs(maxHours * 3600)); pginfo->SetRecordingEndTime(pginfo->GetScheduledEndTime()); } } *this = *pginfo; if (status) *status = kFoundProgram; return; } recstartts = startts = desiredts; recendts = endts = desiredts; lastmodified = desiredts; MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT chanid, channum, callsign, name, " "commmethod, outputfilters " "FROM channel " "WHERE chanid = :CHANID"); query.bindValue(":CHANID", _chanid); if (!query.exec()) { MythDB::DBError("Loading Program overlapping a datetime", query); if (status) *status = kNoProgram; return; } if (!query.next()) { if (status) *status = kNoProgram; return; } chanid = query.value(0).toUInt(); chanstr = query.value(1).toString(); chansign = query.value(2).toString(); channame = query.value(3).toString(); programflags &= ~FL_CHANCOMMFREE; programflags |= (query.value(4).toInt() == COMM_DETECT_COMMFREE) ? FL_CHANCOMMFREE : 0; chanplaybackfilters = query.value(5).toString(); { QMutexLocker locker(&staticDataLock); if (unknownTitle.isEmpty()) unknownTitle = gCoreContext->GetSetting("UnknownTitle"); title = unknownTitle; title.detach(); } if (!genUnknown) { if (status) *status = kFakedZeroMinProgram; return; } // Round endtime up to the next half-hour. endts = QDateTime( endts.date(), QTime(endts.time().hour(), endts.time().minute() / kUnknownProgramLength * kUnknownProgramLength), Qt::UTC); endts = endts.addSecs(kUnknownProgramLength * 60); // if under a minute, bump it up to the next half hour if (startts.secsTo(endts) < 60) endts = endts.addSecs(kUnknownProgramLength * 60); recendts = endts; // Find next program starttime bindings.clear(); QDateTime nextstart = startts; querystr = "WHERE program.chanid = :CHANID AND " " program.starttime > :STARTTS " "GROUP BY program.starttime ORDER BY program.starttime LIMIT 1 "; bindings[":CHANID"] = QString::number(_chanid); bindings[":STARTTS"] = desiredts.addSecs(50 - desiredts.time().second()); LoadFromProgram(progList, querystr, bindings, schedList); if (!progList.empty()) nextstart = (*progList.begin())->GetScheduledStartTime(); if (nextstart > startts && nextstart < recendts) recendts = endts = nextstart; if (status) *status = kFakedLiveTVProgram; desiredrecstartts = startts; desiredrecendts = endts; }
void MIDIInstrumentParameterPanel::updateProgramComboBox() { RG_DEBUG << "updateProgramComboBox()"; if (!getSelectedInstrument()) return; MidiDevice *md = dynamic_cast<MidiDevice *>(getSelectedInstrument()->getDevice()); if (!md) { std::cerr << "WARNING: MIDIInstrumentParameterPanel::updateProgramComboBox(): No MidiDevice for Instrument " << getSelectedInstrument()->getId() << '\n'; return; } RG_DEBUG << "updateProgramComboBox(): variation type is " << md->getVariationType(); MidiBank bank = getSelectedInstrument()->getProgram().getBank(); ProgramList programs = md->getPrograms0thVariation(getSelectedInstrument()->isPercussion(), bank); // Remove the programs that have no name. programs.erase(std::remove_if(programs.begin(), programs.end(), MIDIInstrumentParameterPanel::hasNoName), programs.end()); // If we've got programs, show the Program widgets. // Why not "show = (programs.size()>1)"? Because that would hide the // program checkbox which would take away the user's ability to // enable/disable program changes. If we do away with the checkbox // in the future, we should re-evaluate this decision. bool show = !programs.empty(); m_programLabel->setVisible(show); m_programCheckBox->setVisible(show); m_programComboBox->setVisible(show); int currentProgram = -1; // Compute the current program. for (unsigned i = 0; i < programs.size(); ++i) { // If the program change is the same... if (getSelectedInstrument()->getProgram().getProgram() == programs[i].getProgram()) { currentProgram = i; break; } } // If the programs have changed, we need to repopulate the combobox. if (!partialCompareWithName(programs, m_programs)) { // Update the cache. m_programs = programs; // Copy from m_programs to m_programComboBox. m_programComboBox->clear(); for (unsigned i = 0; i < m_programs.size(); ++i) { m_programComboBox->addItem(QObject::tr("%1. %2") .arg(m_programs[i].getProgram() + 1) .arg(QObject::tr(m_programs[i].getName().c_str()))); } } m_programComboBox->setEnabled(getSelectedInstrument()->sendsProgramChange()); #if 0 // ??? This is a pretty nifty idea, but unfortunately, it requires // that we maintain a bogus combobox entry. For now, we'll go // with the simpler "unselected" approach. // If the current program was not found... if (currentProgram < 0 && !m_programs.empty()) { // Format program change and add to combobox. MidiByte programChange = getSelectedInstrument()->getProgram().getProgram(); m_programComboBox.addItem(QString::number(programChange + 1)); currentProgram = programs.size(); } #endif // Display the current program. m_programComboBox->setCurrentIndex(currentProgram); }