- improved parser
authorFelix Domke <tmbinc@elitedvb.net>
Sun, 20 Mar 2005 22:55:46 +0000 (22:55 +0000)
committerFelix Domke <tmbinc@elitedvb.net>
Sun, 20 Mar 2005 22:55:46 +0000 (22:55 +0000)
 - improved keymaps

components.py
keymap.xml
keymapparser.py
lib/dvb/db.cpp
lib/dvb/db.h
lib/gui/elistbox.cpp
lib/gui/ewindowstyle.cpp
lib/gui/ewindowstyle.h
lib/service/listboxservice.cpp
lib/service/listboxservice.h
screens.py

index a5df8ff..abf25f2 100644 (file)
@@ -277,7 +277,7 @@ class ServiceList(HTMLComponent, GUIComponent):
        def __init__(self):
                GUIComponent.__init__(self)
                self.l = eListboxServiceContent()
-       
+               
        def getCurrent(self):
                r = eServiceReference()
                self.l.getCurrent(r)
@@ -292,6 +292,19 @@ class ServiceList(HTMLComponent, GUIComponent):
 
        def setRoot(self, root):
                self.l.setRoot(root)
+               
+               # mark stuff
+       def clearMarked(self):
+               self.l.clearMarked()
+       
+       def isMarked(self, ref):
+               return self.l.isMarked(ref)
+
+       def addMarked(self, ref):
+               self.l.addMarked(ref)
+       
+       def removeMarked(self, ref):
+               self.l.removeMarked(ref)
 
 class ServiceScan:
        
@@ -338,20 +351,23 @@ class ServiceScan:
                return self.state == self.Done
        
 class ActionMap:
-       def __init__(self, context, actions = { }, prio=0):
+       def __init__(self, contexts = [ ], actions = { }, prio=0):
                self.actions = actions
-               self.context = context
+               self.contexts = contexts
                self.prio = prio
                self.p = eActionMapPtr()
                eActionMap.getInstance(self.p)
 
        def execBegin(self):
-               self.p.bindAction(self.context, self.prio, self.action)
+               for ctx in self.contexts:
+                       self.p.bindAction(ctx, self.prio, self.action)
        
        def execEnd(self):
-               self.p.unbindAction(self.context, self.action)
+               for ctx in self.contexts:
+                       self.p.unbindAction(ctx, self.action)
        
        def action(self, context, action):
+               print " ".join(("action -> ", context, action))
                try:
                        self.actions[action]()
                except KeyError:
index 82b8a50..e940ba7 100644 (file)
                <key id="m" mapto="mainMenu" flags="mr" />
                <key id="c" mapto="switchChannel" flags="mr" />
        </map>
-       <map context="MainMenuActions">
-               <key id=" " mapto="selected" flags="mr" />
-       </map>
        
        <map context="ChannelSelectActions">
-               <key id=" " mapto="selectChannel" flags="mr" />
-               
+               <key id="m" mapto="mark" flags="m" />
                <!-- yes, this is flexible as hell. -->
-               <key id="p" mapto="bouquet:PREMIERE" flags="m" />
-               <key id="d" mapto="bouquet:Das Erste" flags="m" />
+               <key id="p" mapto="bouquet:(provider == PREMIERE)" flags="m" />
+               <key id="d" mapto="bouquet:(provider == ARD)" flags="m" />
+       </map>
+       <map context="OkCancelActions">
+               <key id="\x0a" mapto="ok" flags="mr" />
+               <key id="\x1b" mapto="cancel" flags="mr" />
        </map>
        <map context="WindowActions">
                
index 510a47a..032805b 100644 (file)
@@ -52,6 +52,13 @@ def readKeymap():
                                
                                if len(id) == 1:
                                        keyid = ord(id) | 0x8000
+                               elif id[0] == '\\':
+                                       if id[1] == 'x':
+                                               keyid = int(id[2:], 0x10) | 0x8000
+                                       elif id[1] == 'd':
+                                               keyid = int(id[2:]) | 0x8000
+                                       else:
+                                               raise "key id '" + str(id) + "' is neither hex nor dec"
                                else:
                                        try:
                                                keyid = KEYIDS[id]
index fe4bcc7..4e0332b 100644 (file)
@@ -357,13 +357,192 @@ RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref)
        return 1;
 }
 
-RESULT eDVBChannelQuery::compile(ePtr<eDVBChannelQuery> &res, std::string query)
+/* (<name|provider|type|bouquet|satpos|chid> <==|...> <"string"|int>)[AND (..)] */
+
+       /* never, NEVER write a parser in C++! */
+RESULT parseExpression(ePtr<eDVBChannelQuery> &res, std::list<std::string>::const_iterator begin, std::list<std::string>::const_iterator end)
 {
+       std::list<std::string>::const_iterator end_of_exp;
+       if (*begin == "(")
+       {
+               end_of_exp = begin;
+               while (end_of_exp != end)
+                       if (*end_of_exp == ")")
+                               break;
+                       else
+                               ++end_of_exp;
+       
+               if (end_of_exp == end)
+               {
+                       eDebug("expression parse: end of expression while searching for closing brace");
+                       return -1;
+               }
+               
+               ++begin;
+               // begin..end_of_exp
+               int r = parseExpression(res, begin, end_of_exp);
+               if (r)
+                       return r;
+               ++end_of_exp;
+               
+                       /* we had only one sub expression */
+               if (end_of_exp == end)
+                       return 1;
+               
+                       /* otherwise we have an operator here.. */
+               
+               ePtr<eDVBChannelQuery> r2 = res;
+               res = new eDVBChannelQuery();
+               res->m_p1 = r2;
+               res->m_inverse = 0;
+               r2 = 0;
+               
+               if (*end_of_exp == "||")
+                       res->m_type = eDVBChannelQuery::tOR;
+               else if (*end_of_exp == "&&")
+                       res->m_type = eDVBChannelQuery::tAND;
+               else
+               {
+                       eDebug("found operator %s, but only && and || are allowed!", end_of_exp->c_str());
+                       res = 0;
+                       return 1;
+               }
+               
+               ++end_of_exp;
+               
+               return parseExpression(res->m_p2, end_of_exp, end);
+       }
+       
+       // "begin" <op> "end"
+       std::string type, op, val;
+       
+       res = new eDVBChannelQuery();
+       
+       int cnt = 0;
+       while (begin != end)
+       {
+               switch (cnt)
+               {
+               case 0:
+                       type = *begin;
+                       break;
+               case 1:
+                       op = *begin;
+                       break;
+               case 2:
+                       val = *begin;
+                       break;
+               case 3:
+                       eDebug("malformed query: got '%s', but expected only <type> <op> <val>", begin->c_str());
+                       return 1;
+               }
+               ++begin;
+               ++cnt;
+       }
+       
+       if (cnt != 3)
+       {
+               eDebug("malformed query: missing stuff");
+               res = 0;
+               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
+       {
+               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 == "!=")
+               res->m_inverse = 1;
+       else
+       {
+               eDebug("invalid operator %s", op.c_str());
+               res = 0;
+               return 1;
+       }
+       
+       res->m_string = val;
+       res->m_int = atoi(val.c_str());
+//     res->m_channelid = eDVBChannelID(val);
+       
+       return 0;
+}
+
+RESULT eDVBChannelQuery::compile(ePtr<eDVBChannelQuery> &res, const eServiceReferenceDVB &source, std::string query)
+{
+       std::list<std::string> tokens;
+       
+       m_source = source;
+       
+       std::string current_token;
+       
+//     eDebug("splitting %s....", query.c_str());
+       unsigned int i = 0;
+       const char *splitchars="()";
+       int quotemode = 0, lastsplit = 0, lastalnum = 0;
+       while (i <= query.size())
+       {
+               int c = (i < query.size()) ? query[i] : ' ';
+               ++i;
+               
+               int issplit = !!strchr(splitchars, c);
+               int isaln = isalnum(c);
+               int iswhite = c == ' ';
+               int isquot = c == '\"';
+               
+               if (quotemode)
+               {
+                       iswhite = issplit = 0;
+                       isaln = lastalnum;
+               }
+               
+               if (issplit || iswhite || isquot || lastsplit || (lastalnum != isaln))
+               {
+                       if (current_token.size())
+                               tokens.push_back(current_token);
+                       current_token.clear();
+               }
+               
+               if (!(iswhite || isquot))
+                       current_token += c;
+               
+               if (isquot)
+                       quotemode = !quotemode;
+               lastsplit = issplit;
+               lastalnum = isaln;
+       }
+       
+//     for (std::list<std::string>::const_iterator a(tokens.begin()); a != tokens.end(); ++a)
+//     {
+//             printf("%s\n", a->c_str());
+//     }
+       
+               /* 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;
+       return 0; */
 }
 
 DEFINE_REF(eDVBChannelQuery);
index 22eb0b7..7e31a22 100644 (file)
@@ -6,6 +6,12 @@
 
 class ServiceDescriptionTable;
 
+struct eDVBBouquet
+{
+       std::vector<eServiceReferenceDVB> m_services;
+       int lookupService(eServiceReferenceDVB &ref);
+};
+
 class eDVBDB: public iDVBChannelList
 {
 DECLARE_REF(eDVBDB);
@@ -19,6 +25,8 @@ private:
        std::map<eDVBChannelID, channel> m_channels;
        
        std::map<eServiceReferenceDVB, ePtr<eDVBService> > m_services;
+       
+       std::map<eServiceReference, eDVBBouquet> m_bouquets;
 public:
        eDVBDB();
        virtual ~eDVBDB();
@@ -30,7 +38,7 @@ public:
        
        RESULT addService(const eServiceReferenceDVB &service, eDVBService *service);
        RESULT getService(const eServiceReferenceDVB &reference, ePtr<eDVBService> &service);
-
+       
        RESULT startQuery(ePtr<iDVBChannelListQuery> &query, eDVBChannelQuery *query);
 };
 
@@ -42,8 +50,9 @@ private:
        std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator m_cursor;
        ePtr<eDVBDB> m_db;
        ePtr<eDVBChannelQuery> m_query;
+       eServiceReferenceDVB m_source;
 public:
-       eDVBDBQuery(eDVBDB *db, eDVBChannelQuery *query);
+       eDVBDBQuery(eDVBDB *db, const eServiceReferenceDVB &source, eDVBChannelQuery *query);
        virtual RESULT getNextResult(eServiceReferenceDVB &ref);
 };
 
index a3fae34..a6fe45f 100644 (file)
@@ -196,5 +196,4 @@ void eListbox::entryReset()
        m_top = 0;
        m_selected = 0;
        invalidate();
-       eDebug("inval!");
 }
index 3b8271f..25b8946 100644 (file)
@@ -80,6 +80,10 @@ void eWindowStyleSimple::setStyle(gPainter &painter, int what)
                painter.setForegroundColor(gColor(0x1C));
                painter.setBackgroundColor(m_background_color);
                break;
+       case styleListboxMarked:
+               painter.setForegroundColor(gColor(0x2F));
+               painter.setBackgroundColor(gColor(0x2A));
+               break;
        }
 }
 
index 6431c24..0014bfa 100644 (file)
@@ -17,7 +17,8 @@ public:
        enum {
                styleLabel,
                styleListboxSelected,
-               styleListboxNormal
+               styleListboxNormal,
+               styleListboxMarked
        };
        
        virtual void drawFrame(gPainter &painter, const eRect &frame, int type) = 0;
index 647dbdb..db4f6b8 100644 (file)
@@ -30,6 +30,43 @@ void eListboxServiceContent::getCurrent(eServiceReference &ref)
                ref = eServiceReference();
 }
 
+void eListboxServiceContent::initMarked()
+{
+       m_marked.clear();
+}
+
+void eListboxServiceContent::addMarked(const eServiceReference &ref)
+{
+       m_marked.insert(ref);
+       if (m_listbox)
+               m_listbox->entryChanged(lookupService(ref));
+}
+
+void eListboxServiceContent::removeMarked(const eServiceReference &ref)
+{
+       m_marked.erase(ref);
+       if (m_listbox)
+               m_listbox->entryChanged(lookupService(ref));
+}
+
+int eListboxServiceContent::isMarked(const eServiceReference &ref)
+{
+       return m_marked.find(ref) != m_marked.end();
+}
+
+int eListboxServiceContent::lookupService(const eServiceReference &ref)
+{
+               /* shortcut for cursor */
+       if (ref == *m_cursor)
+               return m_cursor_number;
+               /* otherwise, search in the list.. */
+       int index = 0;
+       for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
+       
+               /* this is ok even when the index was not found. */
+       return index;
+}
+
 DEFINE_REF(eListboxServiceContent);
 
 eListboxServiceContent::eListboxServiceContent()
@@ -118,7 +155,10 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const
 {
        ePtr<gFont> fnt = new gFont("Arial", 14);
        painter.clip(eRect(offset, m_itemsize));
-       style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
+       if (cursorValid() && isMarked(*m_cursor))
+               style.setStyle(painter, eWindowStyle::styleListboxMarked);
+       else
+               style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
        painter.clear();
        
        if (cursorValid())
index 231bab1..d524193 100644 (file)
@@ -4,6 +4,7 @@
 #include <lib/gui/elistbox.h>
 #include <lib/service/iservice.h>
 
+#include <set>
 class eServiceCenter;
 
 class eListboxServiceContent: public virtual iListboxContent
@@ -13,6 +14,14 @@ public:
        eListboxServiceContent();
        void setRoot(const eServiceReference &ref);
        void getCurrent(eServiceReference &ref);
+       
+               /* support for marked services */
+       void initMarked();
+       void addMarked(const eServiceReference &ref);
+       void removeMarked(const eServiceReference &ref);
+       int isMarked(const eServiceReference &ref);
+       int lookupService(const eServiceReference &ref);
+
 
 protected:
        void cursorHome();
@@ -44,6 +53,9 @@ private:
        ePtr<eServiceCenter> m_service_center;
        
        eServiceReference m_root;
+       
+               /* support for marked services */
+       std::set<eServiceReference> m_marked;
 };
 
 #endif
index dd13c55..8264628 100644 (file)
@@ -58,9 +58,10 @@ class mainMenu(Screen):
                Screen.__init__(self, session)
                b = Button("ok")
 
-               self["actions"] = ActionMap("MainMenuActions"
+               self["actions"] = ActionMap(["OkCancelActions"]
                        {
-                               "selected": self.okbuttonClick
+                               "ok": self.okbuttonClick,
+                               "cancel": self.close
                        })
 
                b.onClick = [ self.okbuttonClick ]
@@ -90,24 +91,33 @@ class channelSelection(Screen):
                Screen.__init__(self, session)
                
                self["list"] = ServiceList()
-               self["list"].setRoot(eServiceReference("1:0:1:0:0:0:0:0:0:0:PREMIERE"))
+               self["list"].setRoot(eServiceReference("""1:0:1:0:0:0:0:0:0:0:(provider=="ARD") && (type == 1)"""))
                
                self["okbutton"] = Button("ok", [self.channelSelected])
                
                class ChannelActionMap(ActionMap):
-                       def action(self, context, action):
+                       def action(self, contexts, action):
                                if action[:7] == "bouquet":
                                        print "setting root to " + action[8:]
                                        self.csel["list"].setRoot(eServiceReference("1:0:1:0:0:0:0:0:0:0:" + action[8:]))
                                else:
-                                       ActionMap.action(self, context, action)
+                                       ActionMap.action(self, contexts, action)
 
-               self["actions"] = ChannelActionMap("ChannelSelectActions"
+               self["actions"] = ChannelActionMap(["ChannelSelectActions", "OkCancelActions"]
                        {
-                               "selectChannel": self.channelSelected,
+                               "cancel": self.close,
+                               "ok": self.channelSelected,
+                               "mark": self.doMark
                        })
                self["actions"].csel = self
 
+       def doMark(self):
+               ref = self["list"].getCurrent()
+               if self["list"].isMarked(ref):
+                       self["list"].removeMarked(ref)
+               else:
+                       self["list"].addMarked(ref)
+               
        def channelSelected(self):
                self.session.nav.playService(self["list"].getCurrent())
                self.close()
@@ -117,7 +127,7 @@ class infoBar(Screen):
        def __init__(self, session):
                Screen.__init__(self, session)
                
-               self["actions"] = ActionMap("InfobarActions"
+               self["actions"] = ActionMap( [ "InfobarActions" ]
                        {
                                "switchChannel": self.switchChannel,
                                "mainMenu": self.mainMenu