1 /* 2 * dvbepg.h 3 * 4 * Copyright (C) 2009-2011 Christoph Pfister <christophpfister@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #ifndef DVBEPG_H 22 #define DVBEPG_H 23 24 #include "dvbrecording.h" 25 26 class AtscEpgFilter; 27 class DvbDevice; 28 class DvbEpgFilter; 29 30 #define FIRST_LANG "first" 31 32 class DvbEpgLangEntry 33 { 34 public: 35 QString title; 36 QString subheading; 37 QString details; 38 }; 39 40 class DvbEpgEntry : public SharedData 41 { 42 public: 43 enum EitType { 44 EitActualTsPresentFollowing = 0, 45 EitOtherTsPresentFollowing = 1, 46 EitActualTsSchedule = 2, 47 EitOtherTsSchedule = 3, 48 49 EitLast = 3 50 }; DvbEpgEntry()51 DvbEpgEntry(): type(EitActualTsSchedule) { } DvbEpgEntry(const DvbSharedChannel & channel_)52 explicit DvbEpgEntry(const DvbSharedChannel &channel_) : channel(channel_) { } ~DvbEpgEntry()53 ~DvbEpgEntry() { } 54 55 // checks that all variables are ok 56 bool validate() const; 57 58 DvbSharedChannel channel; 59 EitType type; 60 QDateTime begin; // UTC 61 QTime duration; 62 QString content; 63 QString parental; 64 65 // ISO 639-2 language-dependent entries 66 QHash<QString, DvbEpgLangEntry> langEntry; 67 68 DvbSharedRecording recording; 69 70 QString title(QString lang = QString()) const { 71 QString s; 72 73 if (!lang.isEmpty()) { 74 /* 75 * Only return the user requested data 76 * ISO-639-2 code if the title is filled. 77 * 78 * If it isn't, show first language 79 */ 80 if (langEntry[lang].title.isEmpty()) 81 lang = FIRST_LANG; 82 else if (lang != FIRST_LANG) 83 return langEntry[lang].title; 84 } 85 86 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 87 bool first = true; 88 89 while (i.hasNext()) { 90 i.next(); 91 92 QString code = i.key(); 93 DvbEpgLangEntry entry = i.value(); 94 95 if (!entry.title.isEmpty()) { 96 if (first) 97 first = false; 98 else 99 s += "/"; 100 101 if (langEntry.size() > 1 && (lang != FIRST_LANG && code != FIRST_LANG)) { 102 s += code; 103 s += ": "; 104 } 105 s += entry.title; 106 } 107 108 if (lang == FIRST_LANG) 109 break; 110 } 111 return s; 112 } 113 114 QString subheading(QString lang = QString()) const { 115 QString s; 116 117 if (!lang.isEmpty()) { 118 /* 119 * Only return the user requested data 120 * ISO-639-2 code if the subheading is filled. 121 * 122 * If it isn't, show first language 123 */ 124 if (langEntry[lang].subheading.isEmpty()) 125 lang = FIRST_LANG; 126 else if (lang != FIRST_LANG) 127 return langEntry[lang].subheading; 128 } 129 130 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 131 bool first = true; 132 133 while (i.hasNext()) { 134 i.next(); 135 136 QString code = i.key(); 137 DvbEpgLangEntry entry = i.value(); 138 139 if (!entry.subheading.isEmpty()) { 140 if (first) 141 first = false; 142 else 143 s += "/"; 144 145 if (langEntry.size() > 1 && (lang != FIRST_LANG && code != FIRST_LANG)) { 146 s += code; 147 s += ": "; 148 } 149 s += entry.subheading; 150 } 151 152 if (lang == FIRST_LANG) 153 break; 154 } 155 return s; 156 } 157 158 QString details(QString lang = QString()) const { 159 QString s; 160 161 if (!lang.isEmpty()) { 162 /* 163 * Only return the user requested data 164 * ISO-639-2 code if the details are filled. 165 * 166 * If it isn't, show first language 167 */ 168 if (langEntry[lang].details.isEmpty()) 169 lang = FIRST_LANG; 170 else if (lang != FIRST_LANG) 171 return langEntry[lang].details; 172 } 173 174 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 175 bool first = true; 176 177 while (i.hasNext()) { 178 i.next(); 179 180 QString code = i.key(); 181 DvbEpgLangEntry entry = i.value(); 182 183 if (!entry.details.isEmpty()) { 184 if (first) 185 first = false; 186 else 187 s += "\n\n"; 188 189 if (langEntry.size() > 1 && (lang != FIRST_LANG && code != FIRST_LANG)) { 190 s += code; 191 s += ": "; 192 } 193 s += entry.details; 194 } 195 196 if (lang == FIRST_LANG) 197 break; 198 } 199 return s; 200 } 201 202 // Check only the user-visible elements 203 bool operator==(const DvbEpgEntry &other) const 204 { 205 if (channel != other.channel) 206 return false; 207 if (begin != other.begin) 208 return false; 209 if (duration != other.duration) 210 return false; 211 if (content != other.content) 212 return false; 213 214 QHashIterator<QString, DvbEpgLangEntry> i(langEntry); 215 while (i.hasNext()) { 216 i.next(); 217 218 QString code = i.key(); 219 220 if (!other.langEntry.contains(code)) 221 return false; 222 223 DvbEpgLangEntry thisEntry = i.value(); 224 DvbEpgLangEntry otherEntry = other.langEntry[code]; 225 226 if (thisEntry.title != otherEntry.title) 227 return false; 228 if (thisEntry.subheading != otherEntry.subheading) 229 return false; 230 if (thisEntry.details != otherEntry.details) 231 return false; 232 233 // If first language matches, assume entries are identical 234 return true; 235 } 236 237 return true; 238 } 239 }; 240 241 typedef ExplicitlySharedDataPointer<const DvbEpgEntry> DvbSharedEpgEntry; 242 Q_DECLARE_TYPEINFO(DvbSharedEpgEntry, Q_MOVABLE_TYPE); 243 244 class DvbEpgEntryId 245 { 246 public: DvbEpgEntryId(const DvbEpgEntry * entry_)247 explicit DvbEpgEntryId(const DvbEpgEntry *entry_) : entry(entry_) { } DvbEpgEntryId(const DvbSharedEpgEntry & entry_)248 explicit DvbEpgEntryId(const DvbSharedEpgEntry &entry_) : entry(entry_.constData()) { } ~DvbEpgEntryId()249 ~DvbEpgEntryId() { } 250 251 // compares entries, 'recording' is ignored 252 // if one 'details' is empty, 'details' is ignored 253 254 bool operator<(const DvbEpgEntryId &other) const; 255 256 private: 257 const DvbEpgEntry *entry; 258 }; 259 260 class DvbEpgModel : public QObject 261 { 262 Q_OBJECT 263 typedef QMap<DvbEpgEntryId, DvbSharedEpgEntry>::Iterator Iterator; 264 typedef QMap<DvbEpgEntryId, DvbSharedEpgEntry>::ConstIterator ConstIterator; 265 public: 266 DvbEpgModel(DvbManager *manager_, QObject *parent); 267 ~DvbEpgModel(); 268 269 QMap<DvbEpgEntryId, DvbSharedEpgEntry> getEntries() const; 270 QMap<DvbSharedRecording, DvbSharedEpgEntry> getRecordings() const; 271 void setRecordings(const QMap<DvbSharedRecording, DvbSharedEpgEntry> map); 272 QHash<DvbSharedChannel, int> getEpgChannels() const; 273 QList<DvbSharedEpgEntry> getCurrentNext(const DvbSharedChannel &channel) const; 274 275 DvbSharedEpgEntry addEntry(const DvbEpgEntry &entry); 276 void scheduleProgram(const DvbSharedEpgEntry &entry, int extraSecondsBefore, 277 int extraSecondsAfter, bool checkForRecursion=false, int priority=10); 278 279 void startEventFilter(DvbDevice *device, const DvbSharedChannel &channel); 280 void stopEventFilter(DvbDevice *device, const DvbSharedChannel &channel); 281 282 signals: 283 void entryAdded(const DvbSharedEpgEntry &entry); 284 // updating doesn't change the entry pointer (modifies existing content) 285 void entryAboutToBeUpdated(const DvbSharedEpgEntry &entry); 286 void entryUpdated(const DvbSharedEpgEntry &entry); 287 void entryRemoved(const DvbSharedEpgEntry &entry); 288 void epgChannelAdded(const DvbSharedChannel &channel); 289 void epgChannelRemoved(const DvbSharedChannel &channel); 290 void languageAdded(const QString lang); 291 292 private slots: 293 void channelAboutToBeUpdated(const DvbSharedChannel &channel); 294 void channelUpdated(const DvbSharedChannel &channel); 295 void channelRemoved(const DvbSharedChannel &channel); 296 void recordingRemoved(const DvbSharedRecording &recording); 297 298 private: 299 void timerEvent(QTimerEvent *event); 300 void Debug(QString text, const DvbSharedEpgEntry &entry); 301 302 Iterator removeEntry(Iterator it); 303 304 DvbManager *manager; 305 QDateTime currentDateTimeUtc; 306 QMap<DvbEpgEntryId, DvbSharedEpgEntry> entries; 307 QMap<DvbSharedRecording, DvbSharedEpgEntry> recordings; 308 QHash<DvbSharedChannel, int> epgChannels; 309 QList<QExplicitlySharedDataPointer<DvbEpgFilter> > dvbEpgFilters; 310 QList<QExplicitlySharedDataPointer<AtscEpgFilter> > atscEpgFilters; 311 DvbChannel updatingChannel; 312 bool hasPendingOperation; 313 }; 314 315 #endif /* DVBEPG_H */ 316