add support for listing satellites and providers
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Fri, 2 Dec 2005 11:11:00 +0000 (11:11 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Fri, 2 Dec 2005 11:11:00 +0000 (11:11 +0000)
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
lib/dvb/db.cpp
lib/dvb/db.h
lib/python/Screens/ChannelSelection.py
lib/service/iservice.h
lib/service/listboxservice.cpp
lib/service/servicedvb.cpp

index b909e09a7a3927d4d22652d7d3004eaeb8e3ba83..e10fe20f8f4fe5433252bdcd1984fbf679164d6c 100644 (file)
        <map context="ChannelSelectActions">
                <key id="m" mapto="mark" flags="m" />
                <!-- yes, this is flexible as hell. -->
-               <key id="p" mapto="bouquet:(provider == PREMIERE) &amp;&amp; (type == 1)" flags="m" />
+               <!--key id="p" mapto="bouquet:(provider == PREMIERE) &amp;&amp; (type == 1)" flags="m" />
                <key id="d" mapto="bouquet:(provider == ARD) &amp;&amp; (type == 1)" flags="m" />
                <key id="a" mapto="bouquet:" flags="m" />
                <key id="KEY_M" mapto="mark" flags="m" />
                <key id="KEY_D" mapto="bouquet:(provider == ARD)" flags="m" />
                <key id="KEY_A" mapto="bouquet:" flags="m" />
                <key id="KEY_RED" mapto="bouquet:(type == 1) || (type == 17) ORDER BY name" flags="m" />
-               <!--<key id="KEY_GREEN" mapto="bouquet:(type == 1) || (type == 17) ORDER BY provider" flags="m" />
-               <key id="KEY_YELLOW" mapto="bouquet:(type == 1) || (type == 17) ORDER BY satellitePosition" flags="m" />-->
-               <!--<key id="KEY_BLUE" mapto="bouquet:(type == 1) FROM BOUQUET &quot;bouquets.tv&quot; ORDER BY bouquet" flags="m" />-->
+               <key id="KEY_GREEN" mapto="bouquet:(type == 1) || (type == 17) FROM SATELLITES ORDER BY satellitePosition" flags="m" />
+               <key id="KEY_YELLOW" mapto="bouquet:(type == 1) || (type == 17) FROM PROVIDERS ORDER BY name" flags="m" /-->
+
+               <key id="KEY_RED" mapto="showAllServices" flags="m" />
+               <key id="KEY_GREEN" mapto="showSatellites" flags="m" />
+               <key id="KEY_YELLOW" mapto="showProviders" flags="m" />
                <key id="KEY_BLUE" mapto="showFavourites" flags="m" />
                <key id="KEY_INFO" mapto="showEPGList" flags="m" />
                
index 1bfc06ee8c7356789dbf824d01b98255433584fb..8892e4e186a5974108de543db7b727a931da5a83 100644 (file)
@@ -684,8 +684,17 @@ RESULT eDVBDB::getBouquet(const eServiceReference &ref, eBouquet* &bouquet)
 
 RESULT eDVBDB::startQuery(ePtr<iDVBChannelListQuery> &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<eServiceReferenceDVB, ePtr<eDVBService> >::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<eServiceReferenceDVB>::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<eServiceReferenceDVB, ePtr<eDVBService> >::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<eServiceReferenceDVB>::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();
+}
+
 /* (<name|provider|type|bouquet|satpos|chid> <==|...> <"string"|int>)[||,&& (..)] */
 
 static int decodeType(const std::string &type)
@@ -975,37 +1096,41 @@ RESULT eDVBChannelQuery::compile(ePtr<eDVBChannelQuery> &res, std::string query)
        int sort = eDVBChannelQuery::tName;
                /* check for "ORDER BY ..." */
 
-       while (tokens.size() > 2)
+       std::list<std::string>::iterator it = tokens.begin();
+       while (it != tokens.end())
        {
-               std::list<std::string>::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)
index c5e3ff5c7cc1bc567cd506389e4c47a1e54ce7a8..8bb0e5aeca2eae701a098a02aa6024f55dd580dd 100644 (file)
@@ -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<eServiceReferenceDVB, ePtr<eDVBService> >::iterator m_cursor;
        ePtr<eDVBDB> m_db;
        ePtr<eDVBChannelQuery> 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<eServiceReferenceDVB> m_list;
+       std::list<eServiceReferenceDVB>::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
index 3cca57fad2ad2d48438ac978c3778aebdbc7d2d4..ae344dcce554f215338aec7458f29da372937e74 100644 (file)
@@ -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,
index cbfd24a9618d809a62966de7420186a05586a0c6..e4127fb9443cf20d795a1d50ddb7a89c345a0e74 100644 (file)
@@ -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)
index e1f1beb07b4d1f8b1363261285daf9bc59b3b208..0b2e621c5ca2fedf24dd0183e5609a2aac851d47 100644 (file)
@@ -152,8 +152,8 @@ void eListboxServiceContent::setElementFont(int element, gFont *font)
 void eListboxServiceContent::sort()
 {
        ePtr<iListableService> 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();
index 0de132154078d66753a8c759de23c22490ce2686..143269149e1ff8eab75879ced08588ce88ea88cb 100644 (file)
@@ -359,9 +359,12 @@ RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableServ
 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &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())