Author: duncan
Date: Wed Aug  8 15:47:41 2007
New Revision: 9807

Log:
[ 1768790 ] Text Entry and Program Search
Patch from Adam Charrett


Added:
   branches/rel-1/freevo/src/skins/main/buttongroup_area.py   (contents, props 
changed)
   branches/rel-1/freevo/src/skins/main/textentry_area.py   (contents, props 
changed)
   branches/rel-1/freevo/src/tv/plugins/search_programs.py   (contents, props 
changed)
Modified:
   branches/rel-1/freevo/ChangeLog
   branches/rel-1/freevo/share/skins/main/basic.fxd
   branches/rel-1/freevo/src/skin.py
   branches/rel-1/freevo/src/skins/main/main.py

Modified: branches/rel-1/freevo/ChangeLog
==============================================================================
--- branches/rel-1/freevo/ChangeLog     (original)
+++ branches/rel-1/freevo/ChangeLog     Wed Aug  8 15:47:41 2007
@@ -17,6 +17,7 @@
 --------------------------------
 
  * Updated German translation (F#1770195)
+ * New Text Entry and Program Search (F#1768790)
  * Updated alsamixer with event args and synchronous mixer control (F#1767928)
 
 == Release 1.7.3 (2007-08-01) ==

Modified: branches/rel-1/freevo/share/skins/main/basic.fxd
==============================================================================
--- branches/rel-1/freevo/share/skins/main/basic.fxd    (original)
+++ branches/rel-1/freevo/share/skins/main/basic.fxd    Wed Aug  8 15:47:41 2007
@@ -819,35 +819,62 @@
                 <image x="758" y="max-32" width="32" height="32" 
label="downarrow" filename="down.png"/>
             </scrollabletext>
         </headlines>
-       <!-- 
-       *******************************************************
-       ** Button Bar TVGuide Info
-       ******************************************************* -->
+        
+        <!-- 
+        *******************************************************
+        ** Button Bar TVGuide Info
+        ******************************************************* -->
 
-       <tvguideinfo>
-           <screen layout="screen" x="0" y="0" width="800" height="600"/>
-           <info layout="tvguideinfo program details" x="10" y="70" 
width="780" height="80"/>
-        <scrollabletext layout="info" x="10" y="160" width="740" height="420 - 
buttonbar_height">
-            <image x="758" y="160" width="32" height="32" label="uparrow" 
filename="up.png"/>
-            <image x="758" y="max-32" width="32" height="32" label="downarrow" 
filename="down.png"/>
-        </scrollabletext>
-       </tvguideinfo>
-    
-    <layout label="tvguideinfo program details">
-        <content x="0" y="0" type="text" spacing="20" font="default">
-            <item type="default">
-                <if expression="time">
-                    <text font="info font" align="right" width="max" 
expression="time"/>
-                    <newline/>
-                </if>
-                <if expression="title">
-                    <text font="tv title"  align="left"  expression="title"/>
-                    <newline/>
-                </if>                
-            </item>
-        </content>
-    </layout>
+        <tvguideinfo>
+            <screen layout="screen" x="0" y="0" width="800" height="600"/>
+            <info layout="tvguideinfo program details" x="10" y="70" 
width="780" height="80"/>
+            <scrollabletext layout="info" x="10" y="160" width="740" 
height="420 - buttonbar_height">
+                <image x="758" y="160" width="32" height="32" label="uparrow" 
filename="up.png"/>
+                <image x="758" y="max-32" width="32" height="32" 
label="downarrow" filename="down.png"/>
+            </scrollabletext>
+        </tvguideinfo>
+        
+        <searchprograms>
+            <screen layout="screen" x="0" y="0" width="800" height="600"/>
+            <textentry layout="program search" x="10" y="70" width="780" 
height="40"/>
+            <buttongroup layout="keyboard" x="10" y="120" width="780" 
height="400"/>
+        </searchprograms>
+        
+        <layout label="tvguideinfo program details">
+            <content x="0" y="0" type="text" spacing="20" font="default">
+                <item type="default">
+                    <if expression="time">
+                        <text font="info font" align="right" width="max" 
expression="time"/>
+                        <newline/>
+                    </if>
+                    <if expression="title">
+                        <text font="tv title"  align="left"  
expression="title"/>
+                        <newline/>
+                    </if>                
+                </item>
+            </content>
+        </layout>
 
+        <layout label="program search">
+            <background >
+                <rectangle size="2" color="0x000000" bgcolor="0xff000000" 
radius="0"/>
+            </background>
+            <content x="2" y="2" width="MAX-4" height="MAX-4" type="text" 
spacing="20" font="default" />
+        </layout>
+        <layout label="keyboard">
+            <content font="default">
+                <item type="padding" width="5" height="5" />
+                <item type="default" font="tv" align="center" valign="center">
+                    <rectangle bgcolor="0xff000000" color="0x000000" size="2" 
radius="10" x="0"
+                        y="0" width="max" height="max"/>
+                </item>
+                
+                <item type="selected" font="tv selected" align="center" 
valign="center">
+                    <rectangle bgcolor="tv selection" size="2" radius="10" 
color="0x000000" x="0"
+                        y="0" width="max" height="max"/>
+                </item>
+            </content>
+        </layout>
     </skin>
 </freevo>
 <!-- Keep this comment at the end of the file

Modified: branches/rel-1/freevo/src/skin.py
==============================================================================
--- branches/rel-1/freevo/src/skin.py   (original)
+++ branches/rel-1/freevo/src/skin.py   Wed Aug  8 15:47:41 2007
@@ -186,6 +186,215 @@
         self.build_page()
 
 
+class TextEntry:
+    """
+    Data model for a single line of editable text.
+    """
+
+    def __init__(self, text, left_to_right=True):
+        """
+        Initialise the model with the specified text and direction of input.
+        """
+        self.text = text
+        self.left_to_right = left_to_right
+        self.caret_position = 0
+
+
+    def caret_left(self):
+        """
+        Moves the caret, marking the position the next character will be 
+        inserted at, left one character.
+        """
+        self.caret_position -= 1
+        if self.caret_position < 0:
+            self.caret_position = 0
+
+
+    def caret_right(self):
+        """
+        Moves the caret, marking the position the next character will be 
+        inserted at, right one character.
+        """
+        self.caret_position += 1
+        if self.caret_position > len(self.text):
+            self.caret_position = len(self.text)
+
+
+    def delete_char_at_caret(self):
+        """
+        Delete one character at the current caret position and possibly update 
+        the caret position.
+        """
+        # TODO: Right to Left handling
+        if self.caret_position == 0:
+            return
+        if self.caret_position == 1:
+            self.text = self.text[self.caret_position:]
+        else:
+            self.text = self.text[:self.caret_position - 1] + 
self.text[self.caret_position:]
+        self.caret_position -= 1
+
+    def insert_char_at_caret(self, char):
+        """
+        Insert one character at the current caret positon and possibly update 
+        the caret position.
+        """
+        if self.caret_position == 0:
+            self.text = char + self.text
+        elif self.caret_position == len(self.text):
+            self.text = self.text + char
+        else:
+            self.text = self.text[:self.caret_position] + char + 
self.text[self.caret_position:]
+
+        # TODO: Right to Left handling
+        self.caret_position += 1
+
+
+class Button:
+    """
+    Data model representing one button in a button group/grid.
+    """
+
+    def __init__(self, text, action, arg):
+        """
+        Initialise the model which will display the text specified and 
+        call the action function with the specified argument when selected.
+        """
+        self.text = text
+        self.action = action
+        self.arg = arg
+
+
+    def select(self):
+        """
+        Call the action function associate with this button.
+        """
+        if self.action:
+            self.action(self.arg)
+
+
+class ButtonGroup:
+    """
+    Data model used to describe a grid of Buttons.
+
+    Instance varaiables:
+    buttons         = List of buttons rows containing a list of buttons 
(columns).
+    rows            = Number of rows in the group.
+    columns         = Number of columns per row.
+    selected_button = Currently Selected button.
+    selected_row    = The row of the currently selected button.
+    selected_column = 
+    """
+
+    def __init__(self, rows, columns):
+        """
+        Initialise the button group to contain the specified number of rows and
+        columns of buttons.
+        """
+        self.rows = rows
+        self.columns = columns
+        self.selected_row = -1
+        self.selected_column = -1
+        self.selected_button = None
+        self.buttons = []
+        for r in range(rows):
+            button_row = []
+            for c in range(columns):
+                button_row.append(None)
+            self.buttons.append(button_row)
+
+
+    def set_button(self, row, column, button):
+        """
+        Set the button at the specified row and column to be the one supplied.
+        The first button added to the group will be the first selected button. 
+        """
+        self.buttons[row][column] = button
+        if self.selected_button == None:
+            self.selected_button = button
+            self.selected_row = row
+            self.selected_column = column
+
+
+    def get_button(self, row, column):
+        """
+        Retrieve the button at the specified row and column.
+        """
+        return self.buttons[row][column]
+
+
+    def move_up(self):
+        """
+        Select the button above the currently selected button.
+        """
+        if self.selected_row == 0:
+            return False
+        for r in range(self.selected_row-1, -1,  -1):
+            if self.buttons[r][self.selected_column]:
+                self.selected_row = r
+                self.selected_button = self.buttons[r][self.selected_column]
+                return True
+        return False
+
+
+    def move_down(self):
+        """
+        Select the button below the currently selected button.
+        """
+        if self.selected_row + 1 == self.rows:
+            return False
+        for r in range(self.selected_row+1, self.rows):
+            if self.buttons[r][self.selected_column]:
+                self.selected_row = r
+                self.selected_button = self.buttons[r][self.selected_column]
+                return True
+        return False
+
+
+    def move_left(self):
+        """
+        Select the button to the left of the currently selected button.
+        """
+        if self.selected_column == 0:
+            return False
+        for c in range(self.selected_column - 1,  -1,  -1):
+            if self.buttons[self.selected_row][c]:
+                self.selected_column = c
+                self.selected_button = self.buttons[self.selected_row][c]
+                return True
+        return False
+
+
+    def move_right(self):
+        """
+        Select the button to the right of the currently selected button.
+        """
+        if self.selected_column + 1 == self.columns:
+            return False
+        for c in range(self.selected_column + 1,  self.columns):
+            if self.buttons[self.selected_row][c]:
+                self.selected_column = c
+                self.selected_button = self.buttons[self.selected_row][c]
+                return True
+        return False
+
+
+    def set_selected(self, button):
+        """
+        Set the selected button to the one specified.
+        Returns True if the button was selected, False if the button is not in 
+        the group.
+        """
+        for r in range(self.rows):
+            for c in range(self.columns):
+                if self.buttons[r][c] == button:
+                    self.selected_row = r
+                    self.selected_column = c
+                    self.selected_button = button
+                    return True
+        return False
+
+
 def get_singleton():
     """
     Returns an initialized skin object, containing the users preferred

Added: branches/rel-1/freevo/src/skins/main/buttongroup_area.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/skins/main/buttongroup_area.py    Wed Aug  8 
15:47:41 2007
@@ -0,0 +1,106 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# textentry_area.py - A text entry area for the Freevo skin
+# -----------------------------------------------------------------------
+# $Id$
+#
+# Notes:
+# Todo:
+#
+# -----------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2002 Krister Lagerstrom, et al.
+# Please see the file freevo/Docs/CREDITS 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
+#
+# -----------------------------------------------------------------------
+
+
+import copy
+import types
+from area import Skin_Area
+from skin_utils import *
+from skin import eval_attr
+import config
+
+class Buttongroup_Area(Skin_Area):
+    """
+    this call defines the Button Group area
+    """
+
+    def __init__(self):
+        Skin_Area.__init__(self, 'buttongroup')
+        self.button_group = None
+
+    def update_content_needed(self):
+        """
+        check if the content needs an update
+        """
+        return True
+
+
+    def update_content(self):
+        """
+        update the listing area
+        """
+
+        menuw     = self.menuw
+        settings  = self.settings
+        layout    = self.layout
+        area      = self.area_val
+        content   = self.calc_geometry(layout.content, copy_object=True)
+
+        if not hasattr(menuw, "button_group"):
+            return
+
+        button_group = menuw.button_group
+
+        if self.button_group != button_group:
+            self.button_group = button_group
+
+        unselected_style = content.types['default']
+        selected_style = content.types['selected']
+
+        # Overload the item type for the padding variables
+        padding_type = content.types['padding']
+        if padding_type:
+            padding_horizontal = padding_type.width
+            padding_vertical   = padding_type.height
+        else:
+            padding_horizontal = 2
+            padding_vertical   = 2
+
+        rows = button_group.rows
+        columns = button_group.columns
+        button_width = (content.width - (padding_horizontal * (columns - 1)))/ 
columns
+        button_height = (content.height - (padding_vertical * (rows - 1)))/ 
rows
+        y = content.y
+        for row in button_group.buttons:
+            x = content.x
+            for button in row:
+                if button is not None:
+                    if button == button_group.selected_button:
+                        style = selected_style
+                    else:
+                        style = unselected_style
+                    if style.rectangle:
+                        w,h,r = self.get_item_rectangle(style.rectangle,  
button_width,  button_height)
+                        self.drawroundbox(x, y, r.width, r.height, r)
+                    self.drawstring(button.text,  style.font, content, x, y,  
button_width,  button_height,
+                                    align_h=style.align,  align_v=style.valign)
+                x += button_width + padding_horizontal
+
+            y += button_height + padding_vertical

Modified: branches/rel-1/freevo/src/skins/main/main.py
==============================================================================
--- branches/rel-1/freevo/src/skins/main/main.py        (original)
+++ branches/rel-1/freevo/src/skins/main/main.py        Wed Aug  8 15:47:41 2007
@@ -80,8 +80,11 @@
         from info_area      import Info_Area
         from default_areas  import Screen_Area, Title_Area, Subtitle_Area, 
Plugin_Area
         from scrollabletext_area import Scrollabletext_Area
+        from textentry_area import Textentry_Area
+        from buttongroup_area import Buttongroup_Area
 
-        for a in ( 'screen', 'title', 'subtitle', 'view', 'listing', 'info', 
'plugin', 'scrollabletext'):
+        for a in ( 'screen', 'title', 'subtitle', 'view', 'listing', 'info',
+                        'plugin', 'scrollabletext', 'textentry',  
'buttongroup'):
             self.areas[a] = eval('%s_Area()' % a.capitalize())
         self.areas['tvlisting'] = TVListing_Area()
 

Added: branches/rel-1/freevo/src/skins/main/textentry_area.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/skins/main/textentry_area.py      Wed Aug  8 
15:47:41 2007
@@ -0,0 +1,118 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# scrollabletext_area.py - A scrollable text area for the Freevo skin
+# -----------------------------------------------------------------------
+# $Id$
+#
+# Notes:
+# Todo:
+#
+# -----------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2002 Krister Lagerstrom, et al.
+# Please see the file freevo/Docs/CREDITS 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
+#
+# -----------------------------------------------------------------------
+
+
+import copy
+import types
+from area import Skin_Area
+from skin_utils import *
+from skin import eval_attr
+import config
+
+class Textentry_Area(Skin_Area):
+    """
+    this call defines the Text Entry area
+    """
+
+    def __init__(self):
+        Skin_Area.__init__(self, 'textentry')
+        self.text_entry = None
+
+    def update_content_needed(self):
+        """
+        check if the content needs an update
+        """
+        return True
+
+
+    def update_content(self):
+        """
+        update the listing area
+        """
+
+        menuw     = self.menuw
+        settings  = self.settings
+        layout    = self.layout
+        area      = self.area_val
+        content   = self.calc_geometry(layout.content, copy_object=True)
+
+        if not hasattr(menuw, "text_entry"):
+            return
+
+        text_entry = menuw.text_entry
+
+        if self.text_entry != text_entry:
+            self.text_entry = text_entry
+            self.offset = 0
+
+        text = ''
+        total_width = 0
+        font = content.font
+        width = content.width
+        caret_x = 0
+        offset = self.offset
+
+        caret_position = text_entry.caret_position
+        pygame_font = font.font.font
+
+        if offset > caret_position:
+            offset = caret_position - 1
+            if offset < 0:
+                offset = 0
+        else:
+            total_width = 0
+            new_offset = caret_position
+
+            for i in range(caret_position, -1, -1):
+                temp_text = text_entry.text[i:caret_position]
+                total_width = font.font.stringsize(temp_text)
+                if total_width > width:
+                    break
+                offset = i
+
+        self.offset = offset
+
+        total_width = 0
+        for i in range(offset, len(text_entry.text)):
+            total_width = font.font.stringsize(text_entry.text[offset:i+1])
+            if total_width > width:
+                break
+            text = text_entry.text[offset:i+1]
+
+        caret_text = text[:caret_position - offset]
+        # We need a more exact position than is returned by the OSDFont class 
(which
+        # caches character sizes but doesn't take account of kerning)
+        caret_x,h = pygame_font.size(caret_text)
+
+        # Draw Caret
+        self.drawroundbox(content.x + caret_x, content.y, 2, content.height, 
(content.color, 0, 0x00000000, 0))
+
+        # Draw text
+        self.drawstring(text, font, content, x=content.x, align_v='center', 
ellipses='', dim=False)

Added: branches/rel-1/freevo/src/tv/plugins/search_programs.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/tv/plugins/search_programs.py     Wed Aug  8 
15:47:41 2007
@@ -0,0 +1,286 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# view_recordings.py - Directory handling
+# -----------------------------------------------------------------------
+# $Id$
+#
+# Notes:
+# Todo:
+#
+# -----------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2002 Krister Lagerstrom, et al.
+# Please see the file freevo/Docs/CREDITS 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
+#
+# -----------------------------------------------------------------------
+
+import os
+import os.path
+import datetime
+import traceback
+import re
+import stat
+import copy
+import time
+
+import rc
+import config
+import util
+import plugin
+import osd
+import tv.epg_xmltv
+
+from gui import sounds
+from gui.PopupBox import PopupBox
+from gui.AlertBox import AlertBox
+from item import Item
+from event import *
+from menu import MenuItem, Menu
+from tv.program_display import ProgramItem
+
+# Create the skin_object object
+import skin
+skin_object = skin.get_singleton()
+skin_object.register('searchprograms', ('screen', 'textentry', 'buttongroup', 
'plugin'))
+
+class PluginInterface(plugin.MainMenuPlugin):
+    def __init__(self):
+        plugin.MainMenuPlugin.__init__(self)
+
+        self._type = 'mainmenu_tv'
+        self.parent = None
+
+    def items(self, parent):
+        self.parent = parent
+        return [SearchPrograms(parent)]
+
+class SearchPrograms(Item):
+    def __init__(self, parent):
+        Item.__init__(self, parent, skin_type='tv')
+        self.name = _('Search Programs')
+        self.text_entry = skin.TextEntry('')
+        self.type = 'searchprograms'
+        
+        #
+        # Create button groups for alphabet/numbers/symbols
+        #
+        
+        # Create common buttons
+        self.search_button = skin.Button(_('Search'), 
self.search_for_programs, None)
+        self.left_button   = skin.Button(_('Left'), self.move_caret, 'left')
+        self.right_button  = skin.Button(_('Right'), self.move_caret, 'right')
+        self.delete_button = skin.Button(_('Delete'), self.delete_char, None)
+        
+        
+        self.alphabet_button_group = skin.ButtonGroup(6, 7)
+        keys = _('ABCDEFGHIJKLMNOPQRSTUVWXYZ ')
+        self.__init_keyboard_buttons(keys,  self.alphabet_button_group)
+        
+        self.numbers_button_group = skin.ButtonGroup(6, 7)
+        keys = _('1234567890')
+        self.__init_keyboard_buttons(keys,  self.numbers_button_group)
+        
+        self.symbols_button_group = skin.ButtonGroup(6, 7)
+        keys = _('!"#$%^&*();:\'@~?,.<>-=+\[]{}')
+        self.__init_keyboard_buttons(keys,  self.symbols_button_group)
+        
+        characters_button = skin.Button(_('ABC'),  self.change_button_group, 
self.alphabet_button_group)
+        numbers_button = skin.Button(_('123'),  self.change_button_group, 
self.numbers_button_group)
+        symbols_button = skin.Button(_('Symbls'),  self.change_button_group, 
self.symbols_button_group)
+        
+        self.numbers_button_group.set_button(0, 5, characters_button)
+        self.symbols_button_group.set_button(0, 5, characters_button)
+        
+        self.alphabet_button_group.set_button(1, 5, numbers_button)
+        self.symbols_button_group.set_button(1, 5, numbers_button)
+        
+        self.alphabet_button_group.set_button(2, 5, symbols_button)
+        self.numbers_button_group.set_button(2, 5, symbols_button)
+        
+        self.button_group = self.alphabet_button_group
+        
+
+    def actions(self):
+        return [(self.show_search, self.name)]
+
+
+    def show_search(self, arg=None, menuw=None):
+        self.menuw = menuw
+        #self.__redraw = False
+        #rc.app(self)
+        #skin_object.draw('searchprograms', self)
+        menuw.pushmenu(self)
+    
+    def refresh(self):
+        self.__redraw = False
+        skin_object.draw('searchprograms', self)
+
+    def eventhandler(self, event, menuw=None):
+        """
+        eventhandler
+        """
+        consumed = False
+        
+#        if event is MENU_BACK_ONE_MENU:
+#            rc.app(None)
+#            self.menuw.refresh()
+#            consumed = True
+        
+        if event is MENU_SELECT:
+            sounds.play_sound(sounds.MENU_SELECT)
+            self.button_group.selected_button.select()
+            consumed = True
+
+        elif event in (MENU_LEFT, MENU_RIGHT, MENU_DOWN, MENU_UP):
+            if event is MENU_LEFT:
+                self.__redraw = self.button_group.move_left()
+            elif event is MENU_RIGHT:
+                self.__redraw = self.button_group.move_right()
+            elif event is MENU_DOWN:
+                self.__redraw = self.button_group.move_down()
+            elif event is MENU_UP:
+                self.__redraw = self.button_group.move_up()
+
+            if self.__redraw:
+                sounds.play_sound(sounds.MENU_NAVIGATE)
+            consumed = True
+
+        if self.__redraw:
+            skin_object.draw('searchprograms', self)
+            self.__redraw = False
+        return consumed
+
+
+    def insert_key(self, arg):
+        self.text_entry.insert_char_at_caret(arg)
+        self.__redraw = True
+
+
+    def move_caret(self, arg):
+        if arg == 'left':
+            self.text_entry.caret_left()
+        elif arg == 'right':
+            self.text_entry.caret_right()
+        self.__redraw = True
+    
+
+    def delete_char(self, arg):
+        self.text_entry.delete_char_at_caret()
+        self.__redraw = True
+
+
+    def change_button_group(self, arg):
+        self.button_group = arg
+        self.button_group.set_selected(self.button_group.buttons[0][0])
+        self.__redraw = True
+
+
+    def __init_keyboard_buttons(self, keys, button_group):
+        r = 0
+        c = 0
+        for key in keys:
+            if key == ' ':
+                text = _('Space')
+            else:
+                text = key
+            button_group.set_button(r, c, skin.Button(text, self.insert_key, 
key))
+            c += 1
+            if c == 5:
+                r += 1
+                c = 0
+        # Add common buttons to the group
+        button_group.set_button(0,6, self.search_button)
+        button_group.set_button(1,6, self.left_button)
+        button_group.set_button(2,6, self.right_button)
+        button_group.set_button(3,6, self.delete_button)
+    
+    def search_for_programs(self, arg):
+        text = self.text_entry.text
+        pop = PopupBox(text=_('Searching, please wait...'))
+        pop.show()
+        (result, matches) = self.findMatches(text)
+        pop.destroy()
+        
+        items = []
+        if result:
+            _debug_('search found %s matches' % len(matches))
+
+            f = lambda a, b: cmp(a.start, b.start)
+            matches.sort(f)
+            for prog in matches:
+                items.append(ProgramItem(self, prog, context='search'))
+        else:
+            if matches == 'no matches':
+                msgtext = _('No matches found for %s') % text
+                AlertBox(text=msgtext).show()
+                return
+            AlertBox(text=_('findMatches failed: %s') % matches).show()
+            return
+        search_menu = Menu(_( 'Search Results' ), items,
+                           item_types = 'tv program menu')
+
+        self.menuw.pushmenu(search_menu)
+        self.menuw.refresh()
+
+    def findMatches(self, find=None, movies_only=None):
+        global guide
+
+        _debug_('findMatches: %s' % find, config.DINFO)
+
+        matches = []
+        max_results = 500
+
+        if not find and not movies_only:
+            _debug_('nothing to find', config.DINFO)
+            return (FALSE, 'no search string')
+
+        self.updateGuide()
+
+        pattern = '.*' + find + '\ *'
+        regex = re.compile(pattern, re.IGNORECASE)
+        now = time.time()
+
+        for ch in guide.chan_list:
+            for prog in ch.programs:
+                if now >= prog.stop:
+                    continue
+                if not find or regex.match(prog.title) or 
regex.match(prog.desc) \
+                   or regex.match(prog.sub_title):
+                    if movies_only:
+                        # We can do better here than just look for the MPAA
+                        # rating.  Suggestions are welcome.
+                        if 'MPAA' in prog.utf2str().getattr('ratings').keys():
+                            matches.append(prog.utf2str())
+                            _debug_('PROGRAM MATCH 2: %s' % prog, config.DINFO)
+                    else:
+                        # We should never get here if not find and not
+                        # movies_only.
+                        matches.append(prog.utf2str())
+                        _debug_('PROGRAM MATCH 3: %s' % prog, config.DINFO)
+                if len(matches) >= max_results:
+                    break
+
+        _debug_('Found %d matches.' % len(matches), config.DINFO)
+
+        if matches:
+            return (TRUE, matches)
+        return (FALSE, 'no matches')
+
+
+    def updateGuide(self):
+        global guide
+        guide = tv.epg_xmltv.get_guide()

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to