From 32e4324b9b5e615a84885b9132505e4706ededfe Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Sun, 9 Oct 2005 03:32:46 +0000 Subject: [PATCH] service: add sort of servicelist including all required layers --- lib/dvb/db.cpp | 136 +++++++++++++++++++++------ lib/dvb/db.h | 2 + lib/dvb/idvb.h | 9 +- lib/python/Components/ServiceList.py | 1 + lib/service/iservice.h | 19 ++++ lib/service/listboxservice.cpp | 13 +++ lib/service/listboxservice.h | 2 + lib/service/servicedvb.cpp | 54 ++++++++--- lib/service/servicedvb.h | 11 ++- lib/service/servicefs.cpp | 12 +++ lib/service/servicefs.h | 1 + 11 files changed, 215 insertions(+), 45 deletions(-) diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp index fdcd428d..314a96ec 100644 --- a/lib/dvb/db.cpp +++ b/lib/dvb/db.cpp @@ -21,6 +21,7 @@ eDVBService::~eDVBService() eDVBService &eDVBService::operator=(const eDVBService &s) { m_service_name = s.m_service_name; + m_service_name_sort = s.m_service_name_sort; m_provider_name = s.m_provider_name; m_flags = s.m_flags; m_ca = s.m_ca; @@ -30,7 +31,7 @@ eDVBService &eDVBService::operator=(const eDVBService &s) RESULT eDVBService::getName(const eServiceReference &ref, std::string &name) { - name = convertDVBUTF8(m_service_name); + name = m_service_name; return 0; } @@ -45,7 +46,7 @@ int eDVBService::checkFilter(const eServiceReferenceDVB &ref, const eDVBChannelQ switch (query.m_type) { case eDVBChannelQuery::tName: - res = m_service_name.find(query.m_string) != std::string::npos; + res = m_service_name_sort.find(query.m_string) != std::string::npos; break; case eDVBChannelQuery::tProvider: res = m_provider_name.find(query.m_string) != std::string::npos; @@ -213,7 +214,11 @@ void eDVBDB::load() fgets(line, 256, f); if (strlen(line)) line[strlen(line)-1]=0; - s->m_service_name=line; + + s->m_service_name = line; + s->m_service_name_sort = removeDVBChars(line); + makeUpper(s->m_service_name_sort); + fgets(line, 256, f); if (strlen(line)) line[strlen(line)-1]=0; @@ -416,10 +421,62 @@ RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref) if (res) return 0; } + + ref = eServiceReferenceDVB(); return 1; } -/* ( <==|...> <"string"|int>)[AND (..)] */ +int eDVBDBQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b) +{ + ePtr a_service, b_service; + + int sortmode = m_query ? m_query->m_sort : eDVBChannelQuery::tName; + + if ((sortmode == eDVBChannelQuery::tName) || (sortmode == eDVBChannelQuery::tProvider)) + { + if (m_db->getService(a, a_service)) + return 1; + if (m_db->getService(b, b_service)) + return 1; + } + + switch (sortmode) + { + case eDVBChannelQuery::tName: + return a_service->m_service_name_sort < b_service->m_service_name_sort; + case eDVBChannelQuery::tProvider: + return a_service->m_provider_name < b_service->m_provider_name; + case eDVBChannelQuery::tType: + return a.getServiceType() < b.getServiceType(); + case eDVBChannelQuery::tBouquet: + return 1; + case eDVBChannelQuery::tSatellitePosition: + return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16); + default: + return 1; + } + return 0; +} + +/* ( <==|...> <"string"|int>)[||,&& (..)] */ + +static int decodeType(const std::string &type) +{ + if (type == "name") + return eDVBChannelQuery::tName; + else if (type == "provider") + return eDVBChannelQuery::tProvider; + else if (type == "type") + return eDVBChannelQuery::tType; + else if (type == "bouquet") + return eDVBChannelQuery::tBouquet; + else if (type == "satellitePosition") + return eDVBChannelQuery::tSatellitePosition; + else if (type == "channelID") + return eDVBChannelQuery::tChannelID; + else + return -1; +} /* never, NEVER write a parser in C++! */ RESULT parseExpression(ePtr &res, std::list::const_iterator begin, std::list::const_iterator end) @@ -449,12 +506,16 @@ RESULT parseExpression(ePtr &res, std::list::cons /* we had only one sub expression */ if (end_of_exp == end) - return 1; + { + eDebug("only one sub expression"); + return 0; + } /* otherwise we have an operator here.. */ ePtr r2 = res; res = new eDVBChannelQuery(); + res->m_sort = 0; res->m_p1 = r2; res->m_inverse = 0; r2 = 0; @@ -479,6 +540,7 @@ RESULT parseExpression(ePtr &res, std::list::cons std::string type, op, val; res = new eDVBChannelQuery(); + res->m_sort = 0; int cnt = 0; while (begin != end) @@ -509,27 +571,15 @@ RESULT parseExpression(ePtr &res, std::list::cons return 1; } - if (type == "name") - res->m_type = eDVBChannelQuery::tName; - else if (type == "provider") - res->m_type = eDVBChannelQuery::tProvider; - else if (type == "type") - res->m_type = eDVBChannelQuery::tType; - else if (type == "bouquet") - res->m_type = eDVBChannelQuery::tBouquet; - else if (type == "satellitePosition") - res->m_type = eDVBChannelQuery::tSatellitePosition; - else if (type == "channelID") - res->m_type = eDVBChannelQuery::tChannelID; - else + res->m_type = decodeType(type); + + if (res->m_type == -1) { eDebug("malformed query: invalid type %s", type.c_str()); res = 0; return 1; } - eDebug("type is %d, nice!", res->m_type); - if (op == "==") res->m_inverse = 0; else if (op == "!=") @@ -554,7 +604,7 @@ RESULT eDVBChannelQuery::compile(ePtr &res, std::string query) std::string current_token; -// eDebug("splitting %s....", query.c_str()); + eDebug("splitting %s....", query.c_str()); unsigned int i = 0; const char *splitchars="()"; int quotemode = 0, lastsplit = 0, lastalnum = 0; @@ -594,15 +644,45 @@ RESULT eDVBChannelQuery::compile(ePtr &res, std::string query) // { // printf("%s\n", a->c_str()); // } + + int sort = eDVBChannelQuery::tName; + /* check for "ORDER BY ..." */ + if (tokens.size() > 2) + { + std::list::iterator i = tokens.end(); + --i; --i; --i; + if (*i == "ORDER") + { + ++i; + if (*i == "BY") + { + ++i; + sort = decodeType(*i); + tokens.pop_back(); // ... + tokens.pop_back(); // BY + tokens.pop_back(); // ORDER + } else + sort = -1; + } + } + + if (sort == -1) + { + eWarning("ORDER BY .. string invalid."); + res = 0; + return -1; + } + + eDebug("sort by %d", sort); /* now we recursivly parse that. */ - return parseExpression(res, tokens.begin(), tokens.end()); -/* - res = new eDVBChannelQuery(); - res->m_type = eDVBChannelQuery::tName; - res->m_inverse = 0; - res->m_string = query; - return 0; */ + int r = parseExpression(res, tokens.begin(), tokens.end()); + + if (res) + res->m_sort = sort; + + eDebug("return: %d", r); + return r; } DEFINE_REF(eDVBChannelQuery); diff --git a/lib/dvb/db.h b/lib/dvb/db.h index 084c877a..604d5288 100644 --- a/lib/dvb/db.h +++ b/lib/dvb/db.h @@ -56,6 +56,8 @@ private: public: eDVBDBQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query); virtual RESULT getNextResult(eServiceReferenceDVB &ref); + + int compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b); }; #endif diff --git a/lib/dvb/idvb.h b/lib/dvb/idvb.h index add9ba85..d94bf5fd 100644 --- a/lib/dvb/idvb.h +++ b/lib/dvb/idvb.h @@ -180,7 +180,8 @@ public: bool cacheEmpty() { return m_cache.empty(); } eDVBService(); - std::string m_service_name; + /* m_service_name_sort is uppercase, with special chars removed, to increase sort performance. */ + std::string m_service_name, m_service_name_sort; std::string m_provider_name; int m_flags; @@ -194,7 +195,7 @@ public: RESULT getName(const eServiceReference &ref, std::string &name); int getLength(const eServiceReference &ref); - // for filtering: + /* for filtering: */ int checkFilter(const eServiceReferenceDVB &ref, const eDVBChannelQuery &query); }; @@ -208,6 +209,7 @@ class iDVBChannelListQuery: public iObject { public: virtual RESULT getNextResult(eServiceReferenceDVB &ref)=0; + virtual int compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b)=0; }; class eDVBChannelQuery: public iObject @@ -233,6 +235,9 @@ public: int m_int; eDVBChannelID m_channelid; + /* sort is only valid in root, and must be from the enum above. */ + int m_sort; + static RESULT compile(ePtr &res, std::string query); ePtr m_p1, m_p2; diff --git a/lib/python/Components/ServiceList.py b/lib/python/Components/ServiceList.py index 73727403..93c79296 100644 --- a/lib/python/Components/ServiceList.py +++ b/lib/python/Components/ServiceList.py @@ -32,6 +32,7 @@ class ServiceList(HTMLComponent, GUIComponent): def setRoot(self, root): self.l.setRoot(root) + self.l.sort() # mark stuff def clearMarked(self): diff --git a/lib/service/iservice.h b/lib/service/iservice.h index 54d7b11f..d0dc1e2b 100644 --- a/lib/service/iservice.h +++ b/lib/service/iservice.h @@ -250,10 +250,29 @@ public: /* new, shiny interface: streaming. */ virtual SWIG_VOID(RESULT) getNext(eServiceReference &SWIG_OUTPUT)=0; + + /* use this for sorting. output is not sorted because of either + - performance reasons: the whole list must be buffered or + - the interface would be restricted to a list. streaming + (as well as a future "active" extension) won't be possible. + */ + virtual int compareLessEqual(const eServiceReference &, const eServiceReference &)=0; }; TEMPLATE_TYPEDEF(ePtr, iListableServicePtr); + /* a helper class which can be used as argument to stl's sort(). */ +class iListableServiceCompare +{ + ePtr m_list; +public: + iListableServiceCompare(iListableService *list): m_list(list) { } + bool operator()(const eServiceReference &a, const eServiceReference &b) + { + return m_list->compareLessEqual(a, b); + } +}; + class iServiceOfflineOperations: public iObject { public: diff --git a/lib/service/listboxservice.cpp b/lib/service/listboxservice.cpp index 07838722..d4cbff20 100644 --- a/lib/service/listboxservice.cpp +++ b/lib/service/listboxservice.cpp @@ -108,6 +108,19 @@ void eListboxServiceContent::setElementFont(int element, gFont *font) m_element_font[element] = font; } +void eListboxServiceContent::sort() +{ + ePtr 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(); + if (m_listbox) + m_listbox->entryReset(); + } +} + DEFINE_REF(eListboxServiceContent); eListboxServiceContent::eListboxServiceContent() diff --git a/lib/service/listboxservice.h b/lib/service/listboxservice.h index f560b627..4e5a8dd5 100644 --- a/lib/service/listboxservice.h +++ b/lib/service/listboxservice.h @@ -45,6 +45,8 @@ public: void setElementPosition(int element, eRect where); void setElementFont(int element, gFont *font); + void sort(); + protected: void cursorHome(); void cursorEnd(); diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index ca08d481..a29b77ce 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -36,6 +36,7 @@ RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, st { ASSERT(ref == m_ref); name = m_parser.m_name.size() ? m_parser.m_name : ref.path; + return 0; } int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref) @@ -133,7 +134,7 @@ eDVBServiceList::~eDVBServiceList() { } -RESULT eDVBServiceList::getContent(std::list &list) +RESULT eDVBServiceList::startQuery() { ePtr db; ePtr res; @@ -150,30 +151,50 @@ RESULT eDVBServiceList::getContent(std::list &list) return err; } - ePtr query; - ePtr q; if (m_parent.path.size()) + { eDVBChannelQuery::compile(q, m_parent.path); + if (!q) + { + eDebug("compile query failed"); + return err; + } + } - if ((err = db->startQuery(query, q)) != 0) + if ((err = db->startQuery(m_query, q)) != 0) { eDebug("startQuery failed"); return err; } - + + return 0; +} + +RESULT eDVBServiceList::getContent(std::list &list) +{ eServiceReferenceDVB ref; - while (!query->getNextResult(ref)) + if (!m_query) + return -1; + + while (!m_query->getNextResult(ref)) list.push_back(ref); return 0; } -RESULT eDVBServiceList::getNext(eServiceReference &) +RESULT eDVBServiceList::getNext(eServiceReference &ref) { - /* implement me */ - return -1; + if (!m_query) + return -1; + + return m_query->getNextResult((eServiceReferenceDVB&)ref); +} + +int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b) +{ + return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b); } RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr &ptr) @@ -195,7 +216,14 @@ RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr &ptr) { - ptr = new eDVBServiceList(ref); + ePtr list = new eDVBServiceList(ref); + if (list->startQuery()) + { + ptr = 0; + return -1; + } + + ptr = list; return 0; } @@ -389,6 +417,7 @@ RESULT eDVBServicePlay::start() eDebug("starting DVB service"); r = m_service_handler.tune((eServiceReferenceDVB&)m_reference); m_event(this, evStart); + return 0; } RESULT eDVBServicePlay::stop() @@ -459,8 +488,11 @@ RESULT eDVBServicePlay::info(ePtr &ptr) RESULT eDVBServicePlay::getName(std::string &name) { if (m_dvb_service) + { m_dvb_service->getName(m_reference, name); - else + if (name.empty()) + name = "(...)"; + } else name = "DVB service"; return 0; } diff --git a/lib/service/servicedvb.h b/lib/service/servicedvb.h index accdd20d..57dca9a0 100644 --- a/lib/service/servicedvb.h +++ b/lib/service/servicedvb.h @@ -28,14 +28,17 @@ private: class eDVBServiceList: public iListableService { DECLARE_REF(eDVBServiceList); -private: - eServiceReference m_parent; - friend class eServiceFactoryDVB; - eDVBServiceList(const eServiceReference &parent); public: virtual ~eDVBServiceList(); RESULT getContent(std::list &list); RESULT getNext(eServiceReference &ptr); + int compareLessEqual(const eServiceReference &a, const eServiceReference &b); +private: + RESULT startQuery(); + eServiceReference m_parent; + friend class eServiceFactoryDVB; + eDVBServiceList(const eServiceReference &parent); + ePtr m_query; }; class eDVBServicePlay: public iPlayableService, iSeekableService, public Object, public iServiceInformation diff --git a/lib/service/servicefs.cpp b/lib/service/servicefs.cpp index 057498d7..c5846abd 100644 --- a/lib/service/servicefs.cpp +++ b/lib/service/servicefs.cpp @@ -163,4 +163,16 @@ RESULT eServiceFS::getNext(eServiceReference &ptr) return 0; } +int eServiceFS::compareLessEqual(const eServiceReference &a, const eServiceReference &b) +{ + /* directories first */ + if ((a.flags & ~b.flags) & eServiceReference::isDirectory) + return 1; + else if ((~a.flags & b.flags) & eServiceReference::isDirectory) + return 0; + /* sort by filename */ + else + return a.path < b.path; +} + eAutoInitPtr init_eServiceFactoryFS(eAutoInitNumbers::service+1, "eServiceFactoryFS"); diff --git a/lib/service/servicefs.h b/lib/service/servicefs.h index 73bfd985..3400fb85 100644 --- a/lib/service/servicefs.h +++ b/lib/service/servicefs.h @@ -36,6 +36,7 @@ public: RESULT getContent(std::list &list); RESULT getNext(eServiceReference &ptr); + int compareLessEqual(const eServiceReference &, const eServiceReference &); }; #endif -- 2.30.2