Author: dmeyer
Date: Mon Feb 19 20:06:25 2007
New Revision: 9248

Added:
   trunk/ui/src/menu/listing.py
Modified:
   trunk/ui/src/audio/audiodiskitem.py
   trunk/ui/src/directory.py
   trunk/ui/src/menu/__init__.py
   trunk/ui/src/menu/menu.py
   trunk/ui/src/playlist.py

Log:
Move listing handling code from Menu to new class ItemList. Playlist
is now also an ItemList which makes it possible to share some code
and a future kaa.candy based gui widget can draw both.


Modified: trunk/ui/src/audio/audiodiskitem.py
==============================================================================
--- trunk/ui/src/audio/audiodiskitem.py (original)
+++ trunk/ui/src/audio/audiodiskitem.py Mon Feb 19 20:06:25 2007
@@ -76,7 +76,7 @@
 
         # add all playable items to the playlist of the directory
         # to play one files after the other
-        self.playlist = play_items
+        self.set_playlist(play_items)
 
         # all items together
         items = []

Modified: trunk/ui/src/directory.py
==============================================================================
--- trunk/ui/src/directory.py   (original)
+++ trunk/ui/src/directory.py   Mon Feb 19 20:06:25 2007
@@ -360,7 +360,6 @@
         """
         # FIXME: check for password
 
-        self.playlist   = []
         play_items = []
         dir_items  = []
         pl_items   = []
@@ -470,7 +469,7 @@
         # add all playable items to the playlist of the directory
         # to play one files after the other
         if self['config:isplaylist']:
-            self.playlist = play_items
+            self.set_playlist(play_items)
 
         # build a list of all items
         items = dir_items + pl_items + play_items

Modified: trunk/ui/src/menu/__init__.py
==============================================================================
--- trunk/ui/src/menu/__init__.py       (original)
+++ trunk/ui/src/menu/__init__.py       Mon Feb 19 20:06:25 2007
@@ -32,6 +32,7 @@
 # import the submodules
 from files import Files
 from item import Item
+from listing import ItemList
 from mediaitem import MediaItem
 from action import Action
 from menu import Menu

Added: trunk/ui/src/menu/listing.py
==============================================================================
--- (empty file)
+++ trunk/ui/src/menu/listing.py        Mon Feb 19 20:06:25 2007
@@ -0,0 +1,158 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------------
+# listing.py - a simple item listing
+# -----------------------------------------------------------------------------
+# $Id$
+#
+# The file holds the base class for an item listing. It is used for the
+# Menu and for Playlist items. One base class makes it possible to share
+# some code between the two classes and a future gui widget for kaa.candy
+# can be created to draw both.
+#
+# -----------------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2007 Dirk Meyer, et al.
+#
+# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
+# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
+#
+# Please see the file AUTHORS for a complete list of authors.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -----------------------------------------------------------------------------
+
+__all__ = [ 'ItemList' ]
+
+# python imports
+import logging
+
+# menu imports
+from item import Item
+
+# get logging object
+log = logging.getLogger()
+
+class ItemList(object):
+    """
+    A basic listing of items.
+    """
+    def __init__(self, choices=[], selected=None):
+        # state, will increase on every item change
+        self.state = 0
+
+        # set items
+        self.choices = []
+        self.selected = None
+        self.selected_id = None
+        self.selected_pos = -1
+        self.set_items(choices, selected)
+
+
+
+    def set_items(self, items, selected=None):
+        """
+        Set/replace the items.
+        """
+        # increase state variable
+        self.state += 1
+
+        # set new choices and selection
+        self.choices = items
+
+        # select given item
+        if selected is not None:
+            return self.select(selected)
+
+        # try to reset selection in case we had one
+        if not self.selected:
+            # no old selection
+            if len(self.choices):
+                return self.select(self.choices[0])
+            return self.select(None)
+
+        if self.selected in self.choices:
+            # item is still there, reuse it
+            return self.select(self.selected)
+
+        for c in self.choices:
+            if c.__id__() == self.selected_id:
+                # item with the same id is there, use it
+                return self.select(c)
+        if self.choices:
+            # item is gone now, try to the selection close
+            # to the old item
+            pos = max(0, min(self.selected_pos-1, len(self.choices)-1))
+            return self.select(self.choices[pos])
+        # no item in the list
+        return self.select(None)
+
+
+    def select(self, item):
+        """
+        Set the selection to a specific item in the list. If item in an int
+        select a new item relative to current selected
+        """
+        if self.selected == item:
+            # nothing changed
+            return True
+
+        if not self.choices or item is None:
+            # We have no choices and can't select. This could happen when
+            # a DirItem is no playing playlist
+            self.selected = None
+            self.selected_pos = -1
+            return True
+
+        if isinstance(item, Item):
+            # select item
+            if not item in self.choices:
+                log.error('%s not in list', item)
+                ItemList.select(self, self.choices[0])
+                return False
+            self.selected = item
+            self.selected_pos = self.choices.index(item)
+            self.selected_id  = self.selected.__id__()
+            return True
+        # select relative
+        p = min(max(0, self.selected_pos + item), len(self.choices) - 1)
+        return ItemList.select(self, self.choices[p])
+
+
+    def get_items(self):
+        """
+        Return the list of items.
+        """
+        return self.choices
+
+
+    def get_selection(self):
+        """
+        Return current selected item.
+        """
+        return self.selected
+
+
+    def change_item(self, old, new):
+        """
+        Replace the item 'old' with the 'new'.
+        """
+        # increase state variable
+        self.state += 1
+
+        # change item
+        self.choices[self.choices.index(old)] = new
+        if self.selected == old:
+            self.select(new)

Modified: trunk/ui/src/menu/menu.py
==============================================================================
--- trunk/ui/src/menu/menu.py   (original)
+++ trunk/ui/src/menu/menu.py   Mon Feb 19 20:06:25 2007
@@ -43,11 +43,12 @@
 
 # menu imports
 from item import Item
+from listing import ItemList
 
 # get logging object
 log = logging.getLogger()
 
-class Menu(object):
+class Menu(ItemList):
     """
     A Menu page with Items for the MenuStack. It is not allowed to change
     the selected item or the internal choices directly, use 'select',
@@ -56,6 +57,7 @@
     next_id = 0
 
     def __init__(self, heading, choices=[], reload_func = None, type = None):
+        ItemList.__init__(self, choices)
 
         self.heading = heading
         self.stack   = None
@@ -63,16 +65,9 @@
         # unique id of the menu object
         Menu.next_id += 1
         self.id = Menu.next_id
-        # state, will increase on every item change
-        self.state = 0
         # position in the menu stack
         self.pos = -1
 
-        # set items
-        self.choices = []
-        self.selected = None
-        self.set_items(choices, False)
-
         # special items for the new skin to use in the view or info
         # area. If None, menu.selected will be taken
         self.infoitem = None
@@ -103,105 +98,27 @@
         Set/replace the items in this menu. If refresh is True, the menu
         stack will be refreshed and redrawn.
         """
-        # increase state variable
-        self.state += 1
-
         # delete ref to menu for old choices
         for c in self.choices:
             c.menu = None
 
         # set new choices and selection
-        self.choices = items
+        ItemList.set_items(self, items)
 
         # set menu (self) pointer to the items
         sref = weakref(self)
         for c in self.choices:
             c.menu = sref
 
-        # try to reset selection in case we had one
-        if not self.selected:
-            # no old selection
-            if len(self.choices):
-                self.select(self.choices[0])
-            else:
-                self.select(None)
-
-        elif self.selected in self.choices:
-            # item is still there, reuse it
-            self.select(self.selected)
-
-        else:
-            for c in self.choices:
-                if c.__id__() == self.selected_id:
-                    # item with the same id is there, use it
-                    self.select(c)
-                    break
-            else:
-                if self.choices:
-                    # item is gone now, try to the selection close
-                    # to the old item
-                    pos = max(0, min(self.selected_pos-1, len(self.choices)-1))
-                    self.select(self.choices[pos])
-                else:
-                    # no item in the list
-                    self.select(None)
-
         if refresh and self.stack:
             self.stack.refresh()
 
 
-    def select(self, item):
-        """
-        Set the selection to a specific item in the list. If item in an int
-        select a new item relative to current selected
-        """
-        if isinstance(item, Item):
-            # select item
-            self.selected     = item
-            try:
-                self.selected_pos = self.choices.index(item)
-                self.selected_id  = self.selected.__id__()
-            except ValueError, e:
-                log.exception('crash by select %s in %s' % (item, 
self.choices))
-                if self.choices:
-                    self.select(self.choices[0])
-                else:
-                    self.select(None)
-        elif item == None:
-            # nothing to select
-            self.selected     = None
-            self.selected_pos = -1
-        else:
-            # select relative
-            p = min(max(0, self.selected_pos + item), len(self.choices) - 1)
-            self.select(self.choices[p])
-
-
-    def get_items(self):
-        """
-        Return the list of items in this menu.
-        """
-        return self.choices
-
-
-    def get_selection(self):
-        """
-        Return current selected item.
-        """
-        return self.selected
-
-
     def change_item(self, old, new):
         """
         Replace the item 'old' with the 'new'.
         """
-        # increase state variable
-        self.state += 1
-
-        # change item
-        self.choices[self.choices.index(old)] = new
-        if self.selected == old:
-            self.select(new)
+        ItemList.change_item(self, old, new)
         old.menu = None
         new.menu = weakref(self)
 

Modified: trunk/ui/src/playlist.py
==============================================================================
--- trunk/ui/src/playlist.py    (original)
+++ trunk/ui/src/playlist.py    Mon Feb 19 20:06:25 2007
@@ -48,7 +48,7 @@
 import fxditem
 
 from event import *
-from menu import Action, Item, MediaItem, Menu, MediaPlugin
+from menu import Action, Item, MediaItem, Menu, MediaPlugin, ItemList
 
 # get logging object
 log = logging.getLogger()
@@ -57,7 +57,7 @@
 REPEAT_ITEM     = 1
 REPEAT_PLAYLIST = 2
 
-class Playlist(MediaItem):
+class Playlist(MediaItem, ItemList):
     """
     Class for playlists. A playlist can be created with a list of items, a
     filename containing the playlist or a (list of) beacon query(s).
@@ -74,30 +74,32 @@
                      3) a list (directoryname, recursive=0|1)
         """
         MediaItem.__init__(self, parent, type='playlist')
+        ItemList.__init__(self)
+
         self.name = str_to_unicode(name)
 
         # variables only for Playlist
-        self.playlist     = playlist
+        self._playlist    = playlist
         self.autoplay     = autoplay
         self.repeat       = repeat
         self.display_type = type
         self.next_pos     = None
-        self.__playlist_valid = False
+        self._playlist_valid = False
 
         self.background_playlist = None
-        self.random = random
-
-        # Listing stuff, this makes it look like a Menu to the listing
-        # widget. That needs to be cleaned up, e.g. make a List class and
-        # let the listing widget check for it.
-        self.state    = 0
-        self.selected = None
-        self.selected_pos = None
+        self._random = random
 
         # create a basic info object
         self.info = {}
 
 
+    def set_playlist(self, playlist):
+        """
+        Set a new playlist.
+        """
+        self.set_items(playlist, 0)
+
+
     def _read_m3u(self, plsname, content):
         """
         This is the (m3u) playlist reading function.
@@ -137,86 +139,88 @@
         return playlist
 
 
-    def __create_playlist_items(self):
+    def _playlist_create_items(self):
         """
         Build the playlist. Create a list of items and filenames. This function
         will load the playlist file or expand directories
         """
-        if self.__playlist_valid:
-            # we called this function before
-            return
-        self.__playlist_valid = True
+        self._playlist_valid = True
 
         # create a basic info object
         self.info = {}
-        playlist = self.playlist
-        self.playlist = []
+        items = []
 
-        if isinstance(playlist, (str, unicode)):
+        if isinstance(self._playlist, (str, unicode)):
             # playlist is a filename, load the file and create playlist
-            self.set_url(playlist)
-            log.info('create playlist for %s' % playlist)
+            self.set_url(self._playlist)
+            log.info('create playlist for %s' % self._playlist)
             try:
-                f=open(playlist, "r")
+                f=open(self._playlist, "r")
                 content = map(lambda l: l.strip(' \n\r'), f.readlines())
                 f.close
                 if content and content[0].find("[playlist]") > -1:
-                    playlist = self._read_pls(playlist, content)
+                    self._playlist = self._read_pls(self._playlist, content)
                 else:
-                    playlist = self._read_m3u(playlist, content)
+                    self._playlist = self._read_m3u(self._playlist, content)
             except (OSError, IOError), e:
                 log.error('playlist error: %s' % e)
-                playlist = []
+                self._playlist = []
 
-        if isinstance(playlist, kaa.beacon.Query):
-            playlist = [ playlist ]
+        if isinstance(self._playlist, kaa.beacon.Query):
+            self._playlist = [ self._playlist ]
 
         # Note: playlist is a list of Items, strings (filenames) or a
         # beacon queries now.
 
         plugins = MediaPlugin.plugins(self.display_type)
-        for item in playlist:
+        for item in self._playlist:
 
             if isinstance(item, Item):
                 # Item object, correct parent
                 item = copy.copy(item)
                 item.parent = weakref(self)
-                self.playlist.append(item)
+                items.append(item)
                 continue
 
             if not isinstance(item, kaa.beacon.Query):
                 # make item a beacon query
                 item = kaa.beacon.query(filename=item)
 
-            _playlist = []
-            items = item.get(filter='extmap')
+            playlist = []
+            fitems = item.get(filter='extmap')
             for p in plugins:
-                _playlist.extend(p.get(self, items))
+                playlist.extend(p.get(self, fitems))
 
             # sort beacon query on url
-            _playlist.sort(lambda x,y: cmp(x.url, y.url))
+            playlist.sort(lambda x,y: cmp(x.url, y.url))
             # add to playlist
-            self.playlist.extend(_playlist)
+            items.extend(playlist)
+        self.set_items(items, 0)
+        self._playlist = []
 
 
-    def randomize(self):
+    def _randomize(self):
         """
         resort the playlist by random
         """
-        old = self.playlist
-        self.playlist = []
-        while old:
-            element = random.choice(old)
-            old.remove(element)
-            self.playlist += [ element ]
+        if not self._random:
+            return False
+        playlist = self.choices
+        randomized = []
+        while playlist:
+            element = random.choice(playlist)
+            playlist.remove(element)
+            randomized.append(element)
+        self.set_items(randomized, 0)
+        return True
 
 
     def __getitem__(self, attr):
         """
         return the specific attribute
         """
-        if not self.__playlist_valid:
-            self.__create_playlist_items()
+        if not self._playlist_valid:
+            self._playlist_create_items()
         return MediaItem.__getitem__(self, attr)
 
 
@@ -224,8 +228,8 @@
         """
         return the actions for this item: play and browse
         """
-        if not self.__playlist_valid:
-            self.__create_playlist_items()
+        if not self._playlist_valid:
+            self._playlist_create_items()
 
         browse = Action(_('Browse Playlist'), self.browse)
         play = Action(_('Play'), self.play)
@@ -235,8 +239,8 @@
         else:
             items = [ browse, play ]
 
-        if not self.random:
-            items.append(Action(_('Random play all items'), self.random_play))
+        if not self._random:
+            items.append(Action(_('Random play all items'), self._play_random))
 
         return items
 
@@ -245,65 +249,58 @@
         """
         show the playlist in the menu
         """
-        if not self.__playlist_valid:
-            self.__create_playlist_items()
-        if self.random:
-            self.randomize()
+        if not self._playlist_valid:
+            self._playlist_create_items()
+
+        # randomize if needed
+        self._randomize()
 
         display_type = self.display_type
         if self.display_type == 'tv':
             display_type = 'video'
 
-        menu = Menu(self.name, self.playlist, type = display_type)
+        menu = Menu(self.name, self.choices, type = display_type)
         self.pushmenu(menu)
 
 
-    def random_play(self):
-        """
-        play the playlist in random order
-        """
-        Playlist(playlist=self.playlist, parent=self.parent,
-                 type=self.display_type, random=True,
-                 repeat=self.repeat).play()
-
-
     def play(self):
         """
         play the playlist
         """
-        if not self.playlist:
+        if not self._playlist_valid:
+            self._playlist_create_items()
+
+        if not self.choices:
             log.warning('empty playlist')
             return False
 
-        # First start playing. This is a bad hack and needs to
-        # be fixed when fixing the whole self.playlist stuff
-
-        if not self.__playlist_valid:
-            self.__create_playlist_items()
-
-        if self.random:
-            self.randomize()
+        # randomize if needed
+        self._randomize()
 
         if self.background_playlist:
             self.background_playlist.play()
 
-        if not self.playlist:
-            log.warning('empty playlist')
-            return False
-
-        # XXX looks like a menu now
-        self.choices = self.playlist
-
         # FIXME: add random code
         self.next_pos = 0
-        self.state += 1
 
         # Send a PLAY_START event for ourself
         PLAY_START.post(self)
         self._play_next()
 
 
+    def _play_random(self):
+        """
+        play the playlist in random order
+        """
+        Playlist(playlist=self.choices, parent=self.parent,
+                 type=self.display_type, random=True,
+                 repeat=self.repeat).play()
+
+
     def _play_next(self):
+        """
+        Play the next item (defined by self.next_pos).
+        """
         self.select(self.choices[self.next_pos])
 
         if hasattr(self.selected, 'play'):
@@ -338,23 +335,13 @@
         """
         Select item that is playing right now.
         """
-        if not self.playlist:
-            # no need to change stuff (video dir playing)
-            return True
-
-        if not hasattr(self, 'choices') or self.choices != self.playlist:
-            self.choices = self.playlist
-            self.state += 1
-
-        if self.selected == item:
-            return True
-
-        self.selected_pos = self.choices.index(item)
-        self.selected = item
+        ItemList.select(self, item)
+        if self.selected is None:
+            return False
 
-        if item.menu and item in item.menu.choices:
+        if self.selected.menu and self.selected in self.selected.menu.choices:
             # update menu
-            item.menu.select(item)
+            self.selected.menu.select(self.selected)
 
         # get next item
         self.next_pos = (self.selected_pos+1) % len(self.choices)
@@ -373,22 +360,20 @@
         """
         Handle playlist specific events
         """
-        if event == PLAY_START and event.arg in self.playlist:
-            # FIXME: remove this after application update
-            self.select(event.arg)
+        if event == PLAY_START:
             # a new item started playing, cache next (if supported)
             if self.next_pos is not None and \
                    hasattr(self.choices[self.next_pos], 'cache'):
                 self.choices[self.next_pos].cache()
             return True
 
-        # give the event to the next eventhandler in the list
         if not self.selected:
+            # There is no selected item. All following functions need
+            # with self.selected so pass the event to the parent now.
             if event == PLAY_END:
                 event = Event(PLAY_END, self)
             return MediaItem.eventhandler(self, event)
 
-
         if event == PLAYLIST_TOGGLE_REPEAT:
             self.repeat += 1
             if self.repeat == REPEAT_ITEM:
@@ -401,7 +386,6 @@
             OSD_MESSAGE.post(arg)
             return True
 
-
         if event == PLAY_END:
             if self.repeat == REPEAT_ITEM:
                 # Repeat current item
@@ -410,11 +394,15 @@
             if self.next_pos is not None:
                 # Play next item
                 self._play_next()
-            else:
-                # Nothing to play
-                self.stop()
-                # Send a PLAY_END event for ourself
-                PLAY_END.post(self)
+                return True
+            # Nothing to play
+            self.selected = None
+            # Call stop() again here. We need that to stop the bg playlist
+            # but it is not good because stop() is called from the outside
+            # and will result in this PLAY_END.
+            self.stop()
+            # Send a PLAY_END event for ourself
+            PLAY_END.post(self)
             return True
 
         if event == PLAYLIST_NEXT:
@@ -423,10 +411,8 @@
                 # current one sends the stop event
                 self.selected.stop()
                 return True
-            else:
-                # No next item
-                OSD_MESSAGE.post(_('No Next Item In Playlist'))
-
+            # No next item
+            OSD_MESSAGE.post(_('No Next Item In Playlist'))
 
         if event == PLAYLIST_PREV:
             if self.selected_pos:
@@ -435,9 +421,8 @@
                 self.next_pos = self.selected_pos - 1
                 self.selected.stop()
                 return True
-            else:
-                # No previous item
-                OSD_MESSAGE.post(_('no previous item in playlist'))
+            # No previous item
+            OSD_MESSAGE.post(_('no previous item in playlist'))
 
         if event == STOP:
             # Stop playing and send event to parent item

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to