add support for markers in bouquets
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Thu, 20 Jul 2006 18:17:12 +0000 (18:17 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Thu, 20 Jul 2006 18:17:12 +0000 (18:17 +0000)
< > are usable to jump from marker to marker

data/keymap.xml
lib/dvb/db.cpp
lib/dvb/idvb.h
lib/python/Components/ServiceList.py
lib/python/Screens/ChannelSelection.py
lib/python/Screens/InfoBarGenerics.py
lib/service/iservice.h
lib/service/listboxservice.cpp
lib/service/listboxservice.h
lib/service/servicedvb.cpp
lib/service/servicedvb.h

index bf5e424..0a10b53 100644 (file)
                <key id="KEY_BLUE" mapto="showFavourites" flags="m" />
                <key id="KEY_CHANNELUP" mapto="nextBouquet" flags="m" />
                <key id="KEY_CHANNELDOWN" mapto="prevBouquet" flags="m" />
+               <key id="KEY_PREVIOUS" mapto="prevMarker" flags="m" />
+               <key id="KEY_NEXT" mapto="nextMarker" flags="m" />
        </map>
 
        <map context="ChannelSelectEPGActions">
index eb0721b..eb62f1f 100644 (file)
 
 DEFINE_REF(eDVBService);
 
-RESULT eBouquet::addService(const eServiceReference &ref)
+RESULT eBouquet::addService(const eServiceReference &ref, eServiceReference before)
 {
        list::iterator it =
                std::find(m_services.begin(), m_services.end(), ref);
        if ( it != m_services.end() )
                return -1;
-       m_services.push_back(ref);
+       if (before.valid())
+       {
+               it = std::find(m_services.begin(), m_services.end(), before);
+               m_services.insert(it, ref);
+       }
+       else
+               m_services.push_back(ref);
        return 0;
 }
 
index 5c427e7..46d3e5d 100644 (file)
@@ -34,7 +34,7 @@ struct eBouquet
        list m_services;
 // the following five methods are implemented in db.cpp
        RESULT flushChanges();
-       RESULT addService(const eServiceReference &);
+       RESULT addService(const eServiceReference &, eServiceReference before=eServiceReference());
        RESULT removeService(const eServiceReference &);
        RESULT moveService(const eServiceReference &, unsigned int);
        RESULT setListName(const std::string &name);
index 8525ade..d255b8e 100644 (file)
@@ -19,6 +19,10 @@ class ServiceList(HTMLComponent, GUIComponent):
                if pic:
                        self.l.setPixmap(self.l.picFolder, pic)
 
+               pic = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "marker-fs8.png"))
+               if pic:
+                       self.l.setPixmap(self.l.picMarker, pic)
+
                pic = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "ico_dvb_s-fs8.png"))
                if pic:
                        self.l.setPixmap(self.l.picDVB_S, pic)
@@ -66,6 +70,14 @@ class ServiceList(HTMLComponent, GUIComponent):
                self.instance.moveSelectionTo(index)
                print "Moving to character " + str(char)
 
+       def moveToNextMarker(self):
+               idx = self.l.getNextMarkerPos()
+               self.instance.moveSelectionTo(idx)
+
+       def moveToPrevMarker(self):
+               idx = self.l.getPrevMarkerPos()
+               self.instance.moveSelectionTo(idx)
+
        def moveToIndex(self, index):
                self.instance.moveSelectionTo(index)
 
@@ -107,8 +119,11 @@ class ServiceList(HTMLComponent, GUIComponent):
                if not justSet:
                        self.l.sort()
 
-       def addService(self, service):
-               self.l.addService(service)
+       def removeCurrent(self):
+               self.l.removeCurrent()
+
+       def addService(self, service, beforeCurrent=False):
+               self.l.addService(service, beforeCurrent)
 
        def finishFill(self):
                self.l.FillFinished()
index 84e9951..90c12a5 100644 (file)
@@ -86,18 +86,17 @@ class ChannelContextMenu(Screen):
                                        if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
                                                menu.append((_("remove all new found flags"), self.removeAllNewFoundFlags))
                                if inBouquet:
-                                       menu.append((_("remove service"), self.removeCurrentService))
+                                       menu.append((_("remove entry"), self.removeCurrentService))
                                if current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
                                        menu.append((_("remove new found flag"), self.removeNewFoundFlag))
-
-                       if haveBouquets:
-                               menu.append((_("add bouquet..."), self.showBouquetInputBox))
-                               if inBouquetRootList:
-                                       menu.append((_("remove bouquet"), self.removeBouquet))
+                       else:
+                                       menu.append((_("add bouquet"), self.showBouquetInputBox))
+                                       menu.append((_("remove entry"), self.removeBouquet))
 
                if inBouquet: # current list is editable?
                        if not csel.bouquet_mark_edit:
                                if not csel.movemode:
+                                       menu.append((_("add marker"), self.showMarkerInputBox))
                                        menu.append((_("enable move mode"), self.toggleMoveMode))
                                        if not inBouquetRootList:
                                                if haveBouquets:
@@ -128,7 +127,8 @@ class ChannelContextMenu(Screen):
 
        def bouquetInputCallback(self, bouquet):
                if bouquet is not None:
-                       self.csel.addBouquet(bouquet, None, True)
+                       self.csel.addBouquet(bouquet, None)
+               self.close()
 
        def addServiceToBouquetSelected(self):
                bouquets = self.csel.getBouquetList()
@@ -156,6 +156,14 @@ class ChannelContextMenu(Screen):
                self.csel.removeBouquet()
                self.close()
 
+       def showMarkerInputBox(self):
+               self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, type=Input.TEXT)
+
+       def markerInputCallback(self, marker):
+               if marker is not None:
+                       self.csel.addMarker(marker)
+               self.close()
+
        def addCurrentServiceToBouquet(self, dest):
                self.csel.addCurrentServiceToBouquet(dest)
                if self.bsel is not None:
@@ -263,7 +271,25 @@ class ChannelSelectionEdit:
                                name += '_'
                return name
 
-       def addBouquet(self, bName, services, refresh=False):
+       def addMarker(self, name):
+               current = self.servicelist.getCurrent()
+               mutableList = self.getMutableList()
+               cnt = 0
+               while mutableList:
+                       str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
+                       ref = eServiceReference(str)
+                       if current and current.valid():
+                               if not mutableList.addService(ref, current):
+                                       self.servicelist.addService(ref, True)
+                                       mutableList.flushChanges()
+                                       break
+                       elif not mutableList.addService(ref):
+                               self.servicelist.addService(ref, True)
+                               mutableList.flushChanges()
+                               break
+                       cnt+=1
+
+       def addBouquet(self, bName, services):
                serviceHandler = eServiceCenter.getInstance()
                mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
                if mutableBouquetList:
@@ -285,9 +311,11 @@ class ChannelSelectionEdit:
                                                for service in services:
                                                        if mutableBouquet.addService(service):
                                                                print "add", service.toString(), "to new bouquet failed"
+                                                       else:
+                                                               current = self.servicelist.getCurrent()
+                                                               if current and current.toString() == self.bouquet_rootstr:
+                                                                       self.servicelist.addService(service, True)
                                        mutableBouquet.flushChanges()
-                                       if refresh:
-                                               self.setRoot(self.getRoot())
                                else:
                                        print "get mutable list for new created bouquet failed"
                        else:
@@ -316,7 +344,6 @@ class ChannelSelectionEdit:
                        remove(filename)
                except OSError:
                        print "error during remove of", filename
-               eDVBDB.getInstance().reloadBouquets()
 
 #  multiple marked entry stuff ( edit mode, later multiepg selection )
        def startMarkedEdit(self):
@@ -384,7 +411,7 @@ class ChannelSelectionEdit:
                        if not mutableList.removeService(ref):
                                self.bouquetNumOffsetCache = { }
                                mutableList.flushChanges() #FIXME dont flush on each single removed service
-                               self.setRoot(self.getRoot())
+                               self.servicelist.removeCurrent()
 
        def addCurrentServiceToBouquet(self, dest):
                mutableList = self.getMutableList(dest)
@@ -472,6 +499,8 @@ class ChannelSelectionBase(Screen):
                                "showSatellites": self.showSatellites,
                                "nextBouquet": self.nextBouquet,
                                "prevBouquet": self.prevBouquet,
+                               "nextMarker": self.nextMarker,
+                               "prevMarker": self.prevMarker,
                                "1": self.keyNumberGlobal,
                                "2": self.keyNumberGlobal,
                                "3": self.keyNumberGlobal,
@@ -834,6 +863,12 @@ class ChannelSelectionBase(Screen):
                                        else:
                                                self.showAllServices()
 
+       def nextMarker(self):
+               self.servicelist.moveToNextMarker()
+
+       def prevMarker(self):
+               self.servicelist.moveToPrevMarker()
+
 HISTORYSIZE = 20
 
 #config for lastservice
@@ -930,7 +965,7 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelect
                        self.enterPath(ref)
                elif self.bouquet_mark_edit:
                        self.doMark()
-               else:
+               elif not (ref.flags & 64): # no marker
                        self.zap()
                        self.close(ref)
 
@@ -1156,7 +1191,7 @@ class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelS
                        self.enterPath(ref)
                elif self.bouquet_mark_edit:
                        self.doMark()
-               else:
+               elif not (ref.flags & 64): # no marker
                        playingref = self.session.nav.getCurrentlyPlayingServiceReference()
                        if playingref is None or playingref != ref:
                                self.session.nav.playService(ref)
@@ -1194,7 +1229,7 @@ class SimpleChannelSelection(ChannelSelectionBase):
                ref = self.getCurrentSelection()
                if (ref.flags & 7) == 7:
                        self.enterPath(ref)
-               else:
+               elif not (ref.flags & 64):
                        ref = self.getCurrentSelection()
                        self.close(ref)
 
index 4f0e76b..4c06661 100644 (file)
@@ -299,16 +299,39 @@ class InfoBarChannelSelection:
                self.session.execDialog(self.servicelist)
 
        def zapUp(self):
-               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
-                       if self.servicelist.inBouquet() and self.servicelist.atBegin():
-                               self.servicelist.prevBouquet()
-               self.servicelist.moveUp()
+               if self.servicelist.inBouquet():
+                       prev = self.servicelist.getCurrentSelection()
+                       if prev:
+                               prev = prev.toString()
+                               while True:
+                                       if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
+                                               if self.servicelist.atBegin():
+                                                       self.servicelist.prevBouquet()
+                                       self.servicelist.moveUp()
+                                       cur = self.servicelist.getCurrentSelection()
+                                       if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
+                                               break
+               else:
+                       self.servicelist.moveUp()
                self.servicelist.zap()
                self.doShow()
 
        def zapDown(self):
-               if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
-                       self.servicelist.nextBouquet()
+               if self.servicelist.inBouquet():
+                       prev = self.servicelist.getCurrentSelection()
+                       if prev:
+                               prev = prev.toString()
+                               while True:
+                                       if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
+                                               if self.servicelist.atEnd():
+                                                       self.servicelist.nextBouquet()
+                                               else:
+                                                       self.servicelist.moveDown()
+                                       else:
+                                               self.servicelist.moveDown()
+                                       cur = self.servicelist.getCurrentSelection()
+                                       if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
+                                               break
                else:
                        self.servicelist.moveDown()
                self.servicelist.zap()
index 7dba732..2c395a9 100644 (file)
@@ -38,7 +38,8 @@ public:
                flagDirectory=isDirectory|mustDescent|canDescent,
                shouldSort=8,                   // should be ASCII-sorted according to service_name. great for directories.
                hasSortKey=16,          // has a sort key in data[3]. not having a sort key implies 0.
-               sort1=32                                        // sort key is 1 instead of 0
+               sort1=32,                                       // sort key is 1 instead of 0
+               isMarker=64                     // Marker
        };
        int flags; // flags will NOT be compared.
 
@@ -540,7 +541,7 @@ public:
                /* flush changes */
        virtual RESULT flushChanges()=0;
                /* adds a service to a list */
-       virtual RESULT addService(eServiceReference &ref)=0;
+       virtual RESULT addService(eServiceReference &ref, eServiceReference before=eServiceReference())=0;
                /* removes a service from a list */
        virtual RESULT removeService(eServiceReference &ref)=0;
                /* moves a service in a list, only if list suppports a specific sort method. */
index 284776f..33afaff 100644 (file)
@@ -5,9 +5,29 @@
 #include <lib/dvb/pmt.h>
 #include <lib/python/connections.h>
 
-void eListboxServiceContent::addService(const eServiceReference &service)
+void eListboxServiceContent::addService(const eServiceReference &service, bool beforeCurrent)
 {
-       m_list.push_back(service);
+       if (beforeCurrent && m_size)
+       {
+               m_list.insert(m_cursor, service);
+               ++m_size;
+               --m_cursor;
+       }
+       else
+               m_list.push_back(service);
+}
+
+void eListboxServiceContent::removeCurrent()
+{
+       if (m_size && m_listbox)
+       {
+               if (m_cursor_number == m_size-1)
+                       m_list.erase(m_cursor--);
+               else
+                       m_list.erase(m_cursor++);
+               --m_size;
+               m_listbox->entryRemoved(m_cursor_number);
+       }
 }
 
 void eListboxServiceContent::FillFinished()
@@ -87,6 +107,38 @@ int eListboxServiceContent::getNextBeginningWithChar(char c)
        return 0;
 }
 
+int eListboxServiceContent::getPrevMarkerPos()
+{
+       if (!m_listbox)
+               return 0;
+       list::iterator i(m_cursor);
+       int index = m_cursor_number;
+       while (index)
+       {
+               --i;
+               --index;
+               if (i->flags & eServiceReference::isMarker)
+                       break;
+       }
+       return index;
+}
+
+int eListboxServiceContent::getNextMarkerPos()
+{
+       if (!m_listbox)
+               return 0;
+       list::iterator i(m_cursor);
+       int index = m_cursor_number;
+       while (index < (m_size-1))
+       {
+               ++i;
+               ++index;
+               if (i->flags & eServiceReference::isMarker)
+                       break;
+       }
+       return index;
+}
+
 void eListboxServiceContent::initMarked()
 {
        m_marked.clear();
@@ -377,7 +429,7 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const
                if (m_is_playable_ignore.valid() && service_info && !service_info->isPlayable(*m_cursor, m_is_playable_ignore))
                        painter.setForegroundColor(gRGB(0xbbbbbb));
 
-               int xoffset=0;  // used as offset when painting the folder symbol
+               int xoffset=0;  // used as offset when painting the folder/marker symbol
 
                for (int e = 0; e < celElements; ++e)
                {
@@ -394,8 +446,21 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const
                                {
                                case celServiceNumber:
                                {
+                                       if (m_cursor->flags & eServiceReference::isMarker)
+                                               continue;
                                        char bla[10];
-                                       sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1);
+                               /* how we can do this better? :) */
+                                       int markers_before=0;
+                                       {
+                                               list::iterator tmp=m_cursor;
+                                               while(tmp != m_list.begin())
+                                               {
+                                                       --tmp;
+                                                       if (tmp->flags & eServiceReference::isMarker)
+                                                               ++markers_before;
+                                               }
+                                       }
+                                       sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1 - markers_before);
                                        text = bla;
                                        flags|=gPainter::RT_HALIGN_RIGHT;
                                        break;
@@ -455,17 +520,23 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const
 
                                painter.renderPara(para, offset+ePoint(xoffs, yoffs));
                        }
-                       else if (e == celServiceTypePixmap || e == celFolderPixmap)
+                       else if (e == celServiceTypePixmap || e == celFolderPixmap || e == celMarkerPixmap)
                        {
                                int orbpos = m_cursor->getUnsignedData(4) >> 16;
                                ePtr<gPixmap> &pixmap =
                                        (e == celFolderPixmap) ? m_pixmaps[picFolder] :
+                                       (e == celMarkerPixmap) ? m_pixmaps[picMarker] :
                                        (orbpos == 0xFFFF) ? m_pixmaps[picDVB_C] :
                                        (orbpos == 0xEEEE) ? m_pixmaps[picDVB_T] : m_pixmaps[picDVB_S];
                                if (pixmap)
                                {
                                        eSize pixmap_size = pixmap->size();
-                                       eRect area = m_element_position[e == celFolderPixmap ? celServiceName : celServiceInfo];
+                                       int p = celServiceInfo;
+                                       if (e == celFolderPixmap)
+                                               p = celServiceName;
+                                       else if (e == celMarkerPixmap)
+                                               p = celServiceNumber;
+                                       eRect area = m_element_position[p];
                                        int correction = (area.height() - pixmap_size.height()) / 2;
 
                                        if (m_cursor->flags & eServiceReference::flagDirectory)
@@ -474,6 +545,11 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const
                                                        continue;
                                                xoffset = pixmap_size.width() + 8;
                                        }
+                                       else if (m_cursor->flags & eServiceReference::isMarker)
+                                       {
+                                               if (e != celMarkerPixmap)
+                                                       continue;
+                                       }
                                        else
                                        {
                                                if (e != celServiceTypePixmap)
index d26ee54..59d4d92 100644 (file)
@@ -11,7 +11,8 @@ class eListboxServiceContent: public virtual iListboxContent
 public:
        eListboxServiceContent();
 
-       void addService(const eServiceReference &ref);
+       void addService(const eServiceReference &ref, bool beforeCurrent=false);
+       void removeCurrent();
        void FillFinished();
 
        void setIgnoreService( const eServiceReference &service );
@@ -19,7 +20,9 @@ public:
        void getCurrent(eServiceReference &ref);
        
        int getNextBeginningWithChar(char c);
-
+       int getPrevMarkerPos();
+       int getNextMarkerPos();
+       
                /* support for marked services */
        void initMarked();
        void addMarked(const eServiceReference &ref);
@@ -43,6 +46,7 @@ public:
                /* only in complex mode: */
        enum {
                celServiceNumber,
+               celMarkerPixmap,
                celFolderPixmap,
                celServiceName,
                celServiceTypePixmap,
@@ -55,6 +59,7 @@ public:
                picDVB_T,
                picDVB_C,
                picFolder,
+               picMarker,
                picElements
        };
 
index 10de621..d789da6 100644 (file)
@@ -506,11 +506,11 @@ RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
        return -1;
 }
 
-RESULT eDVBServiceList::addService(eServiceReference &ref)
+RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
 {
        if (!m_bouquet)
                return -1;
-       return m_bouquet->addService(ref);
+       return m_bouquet->addService(ref, before);
 }
 
 RESULT eDVBServiceList::removeService(eServiceReference &ref)
index 8026d65..5d3d008 100644 (file)
@@ -41,7 +41,7 @@ public:
        
        RESULT startEdit(ePtr<iMutableServiceList> &);
        RESULT flushChanges();
-       RESULT addService(eServiceReference &ref);
+       RESULT addService(eServiceReference &ref, eServiceReference before);
        RESULT removeService(eServiceReference &ref);
        RESULT moveService(eServiceReference &ref, int pos);
        RESULT setListName(const std::string &name);