From f15ee3f6cd34e4552f50dcc92a994198ed3b2dfe Mon Sep 17 00:00:00 2001 From: Andreas Monzner Date: Fri, 2 Dec 2005 11:11:00 +0000 Subject: [PATCH] add support for listing satellites and providers use this new stuff in a simple case study (green and yellow button in service list.. feel free to implement a cool satellites/providers tree) prepare for splitted radio/tv mode --- data/keymap.xml | 11 +- lib/dvb/db.cpp | 161 ++++++++++++++++++++++--- lib/dvb/db.h | 28 ++++- lib/python/Screens/ChannelSelection.py | 48 +++++--- lib/service/iservice.h | 2 + lib/service/listboxservice.cpp | 4 +- lib/service/servicedvb.cpp | 7 +- 7 files changed, 219 insertions(+), 42 deletions(-) diff --git a/data/keymap.xml b/data/keymap.xml index b909e09a..e10fe20f 100644 --- a/data/keymap.xml +++ b/data/keymap.xml @@ -129,16 +129,19 @@ - + - + + + + + + diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp index 1bfc06ee..8892e4e1 100644 --- a/lib/dvb/db.cpp +++ b/lib/dvb/db.cpp @@ -684,8 +684,17 @@ RESULT eDVBDB::getBouquet(const eServiceReference &ref, eBouquet* &bouquet) RESULT eDVBDB::startQuery(ePtr &query, eDVBChannelQuery *q, const eServiceReference &source) { - if ( q && q->m_bouquet_name.length() ) - query = new eDVBDBBouquetQuery(this, source, q); + if ( source.path.find("FROM") != std::string::npos ) + { + if ( source.path.find("BOUQUET") != std::string::npos ) + query = new eDVBDBBouquetQuery(this, source, q); + else if ( source.path.find("SATELLITES") != std::string::npos ) + query = new eDVBDBSatellitesQuery(this, source, q); + else if ( source.path.find("PROVIDERS") != std::string::npos ) + query = new eDVBDBProvidersQuery(this, source, q); + else + eFatal("invalid query %s", source.toString().c_str()); + } else query = new eDVBDBQuery(this, source, q); return 0; @@ -784,6 +793,118 @@ RESULT eDVBDBBouquetQuery::getNextResult(eServiceReferenceDVB &ref) return 1; } +eDVBDBListQuery::eDVBDBListQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBQueryBase(db, source, query), m_cursor(m_list.end()) +{ +} + +RESULT eDVBDBListQuery::getNextResult(eServiceReferenceDVB &ref) +{ + if (m_cursor != m_list.end()) + { + ref = *m_cursor++; + return 0; + } + ref.type = eServiceReference::idInvalid; + return 1; +} + +int eDVBDBListQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b) +{ + if ( m_query->m_sort == eDVBChannelQuery::tSatellitePosition ) + return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16); + return a.name < b.name; +} + +eDVBDBSatellitesQuery::eDVBDBSatellitesQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBListQuery(db, source, query) +{ + for (std::map >::iterator it(m_db->m_services.begin()); + it != m_db->m_services.end(); ++it) + { + int res = it->second->checkFilter(it->first, *query); + if (res) + { + unsigned int dvbnamespace = it->first.getDVBNamespace().get()&0xFFFF0000; + bool found=0; + for (std::list::iterator i(m_list.begin()); i != m_list.end(); ++i) + if ( (i->getDVBNamespace().get()&0xFFFF0000) == dvbnamespace ) + { + found=true; + break; + } + if (!found) + { + eServiceReferenceDVB ref; + ref.setDVBNamespace(dvbnamespace); + char buf[64]; +// TODO get real satellite name.. +// but i dont like to parse the satellites.xml here.. and in the python part + snprintf(buf, 64, "Services - %d", dvbnamespace>>16); + ref.name=buf; + snprintf(buf, 64, "(satellitePosition == %d) && ", dvbnamespace>>16); + ref.path=buf+source.path; + unsigned int pos=ref.path.find("FROM"); + ref.flags=eServiceReference::flagDirectory; + ref.path.erase(pos); + ref.path+="ORDER BY name"; +// eDebug("ref.path now %s", ref.path.c_str()); + m_list.push_back(ref); + + ref.path=buf+source.path; + pos=ref.path.find("FROM"); + ref.path.erase(pos+5); + ref.path+="PROVIDERS ORDER BY name"; +// eDebug("ref.path now %s", ref.path.c_str()); + snprintf(buf, 64, "Providers - %d", dvbnamespace>>16); + ref.name=buf; + m_list.push_back(ref); + } + } + } + m_cursor=m_list.begin(); +} + +eDVBDBProvidersQuery::eDVBDBProvidersQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) + :eDVBDBListQuery(db, source, query) +{ + for (std::map >::iterator it(m_db->m_services.begin()); + it != m_db->m_services.end(); ++it) + { + int res = it->second->checkFilter(it->first, *query); + if (res) + { + bool found=0; + + const char *provider_name = it->second->m_provider_name.length() ? + it->second->m_provider_name.c_str() : + "Unknown"; + + for (std::list::iterator i(m_list.begin()); i != m_list.end(); ++i) + if (i->name == provider_name) + { + found=true; + break; + } + if (!found) + { + eServiceReferenceDVB ref; + char buf[64]; + ref.name=provider_name; + snprintf(buf, 64, "(provider == \"%s\") && ", provider_name); + ref.path=buf+source.path; + unsigned int pos = ref.path.find("FROM"); + ref.flags=eServiceReference::flagDirectory; + ref.path.erase(pos); + ref.path+="ORDER BY name"; +// eDebug("ref.path now %s", ref.path.c_str()); + m_list.push_back(ref); + } + } + } + m_cursor=m_list.begin(); +} + /* ( <==|...> <"string"|int>)[||,&& (..)] */ static int decodeType(const std::string &type) @@ -975,37 +1096,41 @@ RESULT eDVBChannelQuery::compile(ePtr &res, std::string query) int sort = eDVBChannelQuery::tName; /* check for "ORDER BY ..." */ - while (tokens.size() > 2) + std::list::iterator it = tokens.begin(); + while (it != tokens.end()) { - std::list::iterator it = tokens.end(); - --it; --it; --it; if (*it == "ORDER") { - ++it; - if (*it == "BY") + tokens.erase(it++); + if (it != tokens.end() && *it == "BY") { - ++it; + tokens.erase(it++); sort = decodeType(*it); - tokens.pop_back(); // ... - tokens.pop_back(); // BY - tokens.pop_back(); // ORDER + tokens.erase(it++); } else sort = -1; } else if (*it == "FROM") { - ++it; - if (*it == "BOUQUET") + tokens.erase(it++); + if (it != tokens.end() && *it == "BOUQUET") { - ++it; + tokens.erase(it++); bouquet_name = *it; - tokens.pop_back(); // ... - tokens.pop_back(); // FROM - tokens.pop_back(); // BOUQUET + tokens.erase(it++); + } + else if (it != tokens.end() && *it == "SATELLITES") + tokens.erase(it++); + else if (it != tokens.end() && *it == "PROVIDERS") + tokens.erase(it++); + else + { + eDebug("FROM unknown %s", (*it).c_str()); + tokens.erase(it++); } } else - break; + ++it; } if (sort == -1) diff --git a/lib/dvb/db.h b/lib/dvb/db.h index c5e3ff5c..8bb0e5ae 100644 --- a/lib/dvb/db.h +++ b/lib/dvb/db.h @@ -12,6 +12,8 @@ class eDVBDB: public iDVBChannelList DECLARE_REF(eDVBDB); friend class eDVBDBQuery; friend class eDVBDBBouquetQuery; + friend class eDVBDBSatellitesQuery; + friend class eDVBDBProvidersQuery; private: struct channel { @@ -52,13 +54,12 @@ class eDVBDBQueryBase: public iDVBChannelListQuery { DECLARE_REF(eDVBDBQueryBase); protected: - std::map >::iterator m_cursor; ePtr m_db; ePtr m_query; eServiceReference m_source; public: eDVBDBQueryBase(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query); - int compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b); + virtual int compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b); }; class eDVBDBQuery: public eDVBDBQueryBase @@ -77,4 +78,27 @@ public: RESULT getNextResult(eServiceReferenceDVB &ref); }; +class eDVBDBListQuery: public eDVBDBQueryBase +{ +protected: + std::list m_list; + std::list::iterator m_cursor; +public: + eDVBDBListQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query); + RESULT getNextResult(eServiceReferenceDVB &ref); + int compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b); +}; + +class eDVBDBSatellitesQuery: public eDVBDBListQuery +{ +public: + eDVBDBSatellitesQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query); +}; + +class eDVBDBProvidersQuery: public eDVBDBListQuery +{ +public: + eDVBDBProvidersQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query); +}; + #endif diff --git a/lib/python/Screens/ChannelSelection.py b/lib/python/Screens/ChannelSelection.py index 3cca57fa..ae344dcc 100644 --- a/lib/python/Screens/ChannelSelection.py +++ b/lib/python/Screens/ChannelSelection.py @@ -29,11 +29,12 @@ class ChannelContextMenu(FixedMenu): menu = [ ] - inBouquetRootList = csel.servicelist.getRoot().toString().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK + inBouquetRootList = csel.servicelist.getRoot().getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK inBouquet = csel.getMutableList() is not None if not csel.bouquet_mark_edit and not csel.movemode and not inBouquetRootList: - menu.append(("add service to bouquet", self.addServiceToBouquetSelected)) + if (csel.getCurrentSelection().type & eServiceReference.flagDirectory) != eServiceReference.flagDirectory: + menu.append(("add service to bouquet", self.addServiceToBouquetSelected)) if inBouquet: menu.append(("remove service", self.removeCurrentService)) @@ -41,11 +42,11 @@ class ChannelContextMenu(FixedMenu): if not csel.bouquet_mark_edit: if not csel.movemode: menu.append(("enable move mode", self.toggleMoveMode)) - if not inBouquetRootList: + if not inBouquetRootList: menu.append(("enable bouquet edit", self.bouquetMarkStart)) else: menu.append(("disable move mode", self.toggleMoveMode)) - elif not inBouquetRootList: + elif not inBouquetRootList: menu.append(("end bouquet edit", self.bouquetMarkEnd)) menu.append(("abort bouquet edit", self.bouquetMarkAbort)) @@ -210,23 +211,27 @@ class ChannelSelectionBase(Screen): def __init__(self, session): Screen.__init__(self, session) + # this makes it much simple to implement a selectable radio or tv mode :) + self.service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17)' + self.service_types_radio = '1:7:1:0:0:0:0:0:0:0:(type == 2)' + + self.service_types = self.service_types_tv + #self.bouquet_root = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet') - self.bouquet_root = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet') + self.bouquet_root = eServiceReference('%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)) self["key_red"] = Button("All") - #self["key_green"] = Button("Provider") - #self["key_yellow"] = Button("Satellite") - self["key_green"] = Button("") - self["key_yellow"] = Button("") + self["key_green"] = Button("Satellites") + self["key_yellow"] = Button("Provider") self["key_blue"] = Button("Favourites") self["list"] = ServiceList() self.servicelist = self["list"] #self["okbutton"] = Button("ok", [self.channelSelected]) - + self.numericalTextInput = NumericalTextInput() - + self.lastService = None self.lastServiceTimer = eTimer() @@ -234,7 +239,7 @@ class ChannelSelectionBase(Screen): self.lastServiceTimer.start(100) def getBouquetNumOffset(self, bouquet): - if self.bouquet_root.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK + if self.bouquet_root.getPath().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK return 0 offsetCount = 0 serviceHandler = eServiceCenter.getInstance() @@ -258,8 +263,8 @@ class ChannelSelectionBase(Screen): return offsetCount def setRootBase(self, root): - inBouquetRootList = root.toString().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK - if not inBouquetRootList and ((root.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory): + inBouquetRootList = root.getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK + if not inBouquetRootList and (root.getPath().find('FROM BOUQUET') != -1): self.servicelist.setMode(ServiceList.MODE_FAVOURITES) self.servicelist.setNumberOffset(self.getBouquetNumOffset(root)) else: @@ -272,6 +277,18 @@ class ChannelSelectionBase(Screen): def moveDown(self): self.servicelist.moveDown() + def showAllServices(self): + ref = eServiceReference('%s ORDER BY name'%(self.service_types)) + self.setRoot(ref) + + def showSatellites(self): + ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)) + self.setRoot(ref) + + def showProviders(self): + ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types)) + self.setRoot(ref) + def showFavourites(self): self.setRoot(self.bouquet_root) @@ -331,6 +348,9 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit): "mark": self.doMark, "contextMenu": self.doContext, "showFavourites": self.showFavourites, + "showAllServices": self.showAllServices, + "showProviders": self.showProviders, + "showSatellites": self.showSatellites, "showEPGList": self.showEPGList, "1": self.keyNumberGlobal, "2": self.keyNumberGlobal, diff --git a/lib/service/iservice.h b/lib/service/iservice.h index cbfd24a9..e4127fb9 100644 --- a/lib/service/iservice.h +++ b/lib/service/iservice.h @@ -43,10 +43,12 @@ public: int data[8]; std::string path; + std::string getPath() { return path; } // only for override service names in bouquets or to give servicerefs a name which not have a // real existing service ( for dvb eServiceDVB ) std::string name; + std::string getName() { return name; } eServiceReference() : type(idInvalid), flags(0) diff --git a/lib/service/listboxservice.cpp b/lib/service/listboxservice.cpp index e1f1beb0..0b2e621c 100644 --- a/lib/service/listboxservice.cpp +++ b/lib/service/listboxservice.cpp @@ -152,8 +152,8 @@ void eListboxServiceContent::setElementFont(int element, gFont *font) void eListboxServiceContent::sort() { ePtr lst; - if (!m_service_center->list(m_root, lst)) - { + if (!m_service_center->list(m_root, lst)) + { m_list.sort(iListableServiceCompare(lst)); /* FIXME: is this really required or can we somehow keep the current entry? */ cursorHome(); diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 0de13215..14326914 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -359,9 +359,12 @@ RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr &ptr) { /* do we have a PVR service? */ - if (ref.flags & eServiceReference::flagDirectory) // bouquet + if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet { - ptr = new eStaticServiceDVBBouquetInformation; + if ( !ref.name.empty() ) + ptr = new eStaticServiceDVBInformation; + else + ptr = new eStaticServiceDVBBouquetInformation; return 0; } else if (!ref.path.empty()) -- 2.30.2