File indexing completed on 2024-05-19 04:53:15
0001 /* 0002 * dvbepg.h 0003 * 0004 * Copyright (C) 2009-2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #ifndef DVBEPG_H 0022 #define DVBEPG_H 0023 0024 #include "dvbrecording.h" 0025 0026 class AtscEpgFilter; 0027 class DvbDevice; 0028 class DvbEpgFilter; 0029 0030 #define FIRST_LANG "first" 0031 0032 class DvbEpgLangEntry 0033 { 0034 public: 0035 QString title; 0036 QString subheading; 0037 QString details; 0038 }; 0039 0040 class DvbEpgEntry : public SharedData 0041 { 0042 public: 0043 enum EitType { 0044 EitActualTsPresentFollowing = 0, 0045 EitOtherTsPresentFollowing = 1, 0046 EitActualTsSchedule = 2, 0047 EitOtherTsSchedule = 3, 0048 0049 EitLast = 3 0050 }; 0051 DvbEpgEntry(): type(EitActualTsSchedule) { } 0052 explicit DvbEpgEntry(const DvbSharedChannel &channel_) : channel(channel_) { } 0053 ~DvbEpgEntry() { } 0054 0055 // checks that all variables are ok 0056 bool validate() const; 0057 0058 DvbSharedChannel channel; 0059 EitType type; 0060 QDateTime begin; // UTC 0061 QTime duration; 0062 QString content; 0063 QString parental; 0064 0065 // ISO 639-2 language-dependent entries 0066 QHash<QString, DvbEpgLangEntry> langEntry; 0067 0068 DvbSharedRecording recording; 0069 0070 QString title(QString lang = QString()) const { 0071 QString s; 0072 0073 if (!lang.isEmpty()) { 0074 /* 0075 * Only return the user requested data 0076 * ISO-639-2 code if the title is filled. 0077 * 0078 * If it isn't, show first language 0079 */ 0080 if (langEntry[lang].title.isEmpty()) 0081 lang = FIRST_LANG; 0082 else if (lang != FIRST_LANG) 0083 return langEntry[lang].title; 0084 } 0085 0086 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 0087 bool first = true; 0088 0089 while (i.hasNext()) { 0090 i.next(); 0091 0092 QString code = i.key(); 0093 DvbEpgLangEntry entry = i.value(); 0094 0095 if (!entry.title.isEmpty()) { 0096 if (first) 0097 first = false; 0098 else 0099 s += "/"; 0100 0101 if (langEntry.size() > 1 && (lang != FIRST_LANG && code != FIRST_LANG)) { 0102 s += code; 0103 s += ": "; 0104 } 0105 s += entry.title; 0106 } 0107 0108 if (lang == FIRST_LANG) 0109 break; 0110 } 0111 return s; 0112 } 0113 0114 QString subheading(QString lang = QString()) const { 0115 QString s; 0116 0117 if (!lang.isEmpty()) { 0118 /* 0119 * Only return the user requested data 0120 * ISO-639-2 code if the subheading is filled. 0121 * 0122 * If it isn't, show first language 0123 */ 0124 if (langEntry[lang].subheading.isEmpty()) 0125 lang = FIRST_LANG; 0126 else if (lang != FIRST_LANG) 0127 return langEntry[lang].subheading; 0128 } 0129 0130 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 0131 bool first = true; 0132 0133 while (i.hasNext()) { 0134 i.next(); 0135 0136 QString code = i.key(); 0137 DvbEpgLangEntry entry = i.value(); 0138 0139 if (!entry.subheading.isEmpty()) { 0140 if (first) 0141 first = false; 0142 else 0143 s += "/"; 0144 0145 if (langEntry.size() > 1 && (lang != FIRST_LANG && code != FIRST_LANG)) { 0146 s += code; 0147 s += ": "; 0148 } 0149 s += entry.subheading; 0150 } 0151 0152 if (lang == FIRST_LANG) 0153 break; 0154 } 0155 return s; 0156 } 0157 0158 QString details(QString lang = QString()) const { 0159 QString s; 0160 0161 if (!lang.isEmpty()) { 0162 /* 0163 * Only return the user requested data 0164 * ISO-639-2 code if the details are filled. 0165 * 0166 * If it isn't, show first language 0167 */ 0168 if (langEntry[lang].details.isEmpty()) 0169 lang = FIRST_LANG; 0170 else if (lang != FIRST_LANG) 0171 return langEntry[lang].details; 0172 } 0173 0174 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 0175 bool first = true; 0176 0177 while (i.hasNext()) { 0178 i.next(); 0179 0180 QString code = i.key(); 0181 DvbEpgLangEntry entry = i.value(); 0182 0183 if (!entry.details.isEmpty()) { 0184 if (first) 0185 first = false; 0186 else 0187 s += "\n\n"; 0188 0189 if (langEntry.size() > 1 && (lang != FIRST_LANG && code != FIRST_LANG)) { 0190 s += code; 0191 s += ": "; 0192 } 0193 s += entry.details; 0194 } 0195 0196 if (lang == FIRST_LANG) 0197 break; 0198 } 0199 return s; 0200 } 0201 0202 // Check only the user-visible elements 0203 bool operator==(const DvbEpgEntry &other) const 0204 { 0205 if (channel != other.channel) 0206 return false; 0207 if (begin != other.begin) 0208 return false; 0209 if (duration != other.duration) 0210 return false; 0211 if (content != other.content) 0212 return false; 0213 0214 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 0215 while (i.hasNext()) { 0216 i.next(); 0217 0218 QString code = i.key(); 0219 0220 if (!other.langEntry.contains(code)) 0221 return false; 0222 0223 DvbEpgLangEntry thisEntry = i.value(); 0224 DvbEpgLangEntry otherEntry = other.langEntry[code]; 0225 0226 if (thisEntry.title != otherEntry.title) 0227 return false; 0228 if (thisEntry.subheading != otherEntry.subheading) 0229 return false; 0230 if (thisEntry.details != otherEntry.details) 0231 return false; 0232 0233 // If first language matches, assume entries are identical 0234 return true; 0235 } 0236 0237 return true; 0238 } 0239 }; 0240 0241 typedef ExplicitlySharedDataPointer<const DvbEpgEntry> DvbSharedEpgEntry; 0242 Q_DECLARE_TYPEINFO(DvbSharedEpgEntry, Q_MOVABLE_TYPE); 0243 0244 class DvbEpgEntryId 0245 { 0246 public: 0247 explicit DvbEpgEntryId(const DvbEpgEntry *entry_) : entry(entry_) { } 0248 explicit DvbEpgEntryId(const DvbSharedEpgEntry &entry_) : entry(entry_.constData()) { } 0249 ~DvbEpgEntryId() { } 0250 0251 // compares entries, 'recording' is ignored 0252 // if one 'details' is empty, 'details' is ignored 0253 0254 bool operator<(const DvbEpgEntryId &other) const; 0255 0256 private: 0257 const DvbEpgEntry *entry; 0258 }; 0259 0260 class DvbEpgModel : public QObject 0261 { 0262 Q_OBJECT 0263 typedef QMap<DvbEpgEntryId, DvbSharedEpgEntry>::Iterator Iterator; 0264 typedef QMap<DvbEpgEntryId, DvbSharedEpgEntry>::ConstIterator ConstIterator; 0265 public: 0266 DvbEpgModel(DvbManager *manager_, QObject *parent); 0267 ~DvbEpgModel(); 0268 0269 QMap<DvbEpgEntryId, DvbSharedEpgEntry> getEntries() const; 0270 QMap<DvbSharedRecording, DvbSharedEpgEntry> getRecordings() const; 0271 void setRecordings(const QMap<DvbSharedRecording, DvbSharedEpgEntry> map); 0272 QHash<DvbSharedChannel, int> getEpgChannels() const; 0273 QList<DvbSharedEpgEntry> getCurrentNext(const DvbSharedChannel &channel) const; 0274 0275 DvbSharedEpgEntry addEntry(const DvbEpgEntry &entry); 0276 void scheduleProgram(const DvbSharedEpgEntry &entry, int extraSecondsBefore, 0277 int extraSecondsAfter, bool checkForRecursion=false, int priority=10); 0278 0279 void startEventFilter(DvbDevice *device, const DvbSharedChannel &channel); 0280 void stopEventFilter(DvbDevice *device, const DvbSharedChannel &channel); 0281 0282 signals: 0283 void entryAdded(const DvbSharedEpgEntry &entry); 0284 // updating doesn't change the entry pointer (modifies existing content) 0285 void entryAboutToBeUpdated(const DvbSharedEpgEntry &entry); 0286 void entryUpdated(const DvbSharedEpgEntry &entry); 0287 void entryRemoved(const DvbSharedEpgEntry &entry); 0288 void epgChannelAdded(const DvbSharedChannel &channel); 0289 void epgChannelRemoved(const DvbSharedChannel &channel); 0290 void languageAdded(const QString lang); 0291 0292 private slots: 0293 void channelAboutToBeUpdated(const DvbSharedChannel &channel); 0294 void channelUpdated(const DvbSharedChannel &channel); 0295 void channelRemoved(const DvbSharedChannel &channel); 0296 void recordingRemoved(const DvbSharedRecording &recording); 0297 0298 private: 0299 void timerEvent(QTimerEvent *event) override; 0300 void Debug(QString text, const DvbSharedEpgEntry &entry); 0301 0302 Iterator removeEntry(Iterator it); 0303 0304 DvbManager *manager; 0305 QDateTime currentDateTimeUtc; 0306 QMap<DvbEpgEntryId, DvbSharedEpgEntry> entries; 0307 QMap<DvbSharedRecording, DvbSharedEpgEntry> recordings; 0308 QHash<DvbSharedChannel, int> epgChannels; 0309 QList<QExplicitlySharedDataPointer<DvbEpgFilter> > dvbEpgFilters; 0310 QList<QExplicitlySharedDataPointer<AtscEpgFilter> > atscEpgFilters; 0311 DvbChannel updatingChannel; 0312 bool hasPendingOperation; 0313 }; 0314 0315 #endif /* DVBEPG_H */