FeedList.py :  » RSS » PenguinTV » PenguinTV-4.1.0 » penguintv » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » RSS » PenguinTV 
PenguinTV » PenguinTV 4.1.0 » penguintv » FeedList.py
import sys, os, re
import glob
import logging
import random
import traceback
import time

import gtk
import gobject
import pango

import penguintv
import ptvDB
import utils
import IconManager
import MainWindow

if utils.RUNNING_HILDON:
  import hildon

NONE=-1 #unused, needs a value
ALL=0
DOWNLOADED=1
NOTIFY=2
SEARCH=3
BUILTIN_TAGS=[_("All Feeds"),_("Downloaded Media"), _("Notifying Feeds"), _("Search Results")]

TITLE=0
MARKUPTITLE=1
FEEDID=2
STOCKID=3
READINFO=4
PIXBUF=5
DETAILS_LOADED=6
UNREAD=7
TOTAL=8
FLAG=9
VISIBLE=10
POLLFAIL=11
FIRSTENTRYTITLE=12

NOTVISIBLE=13

#STATES
S_DEFAULT          = 0
S_SEARCH           = 1 
S_MAJOR_DB_OPERATION    = 2

MAX_WIDTH  = 48
MAX_HEIGHT = 48
MIN_SIZE   = 24

class FeedList(gobject.GObject):

  __gsignals__ = {
        'link-activated': (gobject.SIGNAL_RUN_FIRST, 
                           gobject.TYPE_NONE, 
                           ([gobject.TYPE_PYOBJECT])),
    'feed-selected': (gobject.SIGNAL_RUN_FIRST, 
                           gobject.TYPE_NONE, 
                           ([gobject.TYPE_INT])),
        'feed-clicked': (gobject.SIGNAL_RUN_FIRST, 
                           gobject.TYPE_NONE, 
                           ([])),
    'search-feed-selected': (gobject.SIGNAL_RUN_FIRST, 
                           gobject.TYPE_NONE, 
                           ([gobject.TYPE_INT])),                  
    'no-feed-selected': (gobject.SIGNAL_RUN_FIRST, 
                           gobject.TYPE_NONE, 
                           []),
    'state-change': (gobject.SIGNAL_RUN_FIRST, 
                           gobject.TYPE_NONE, 
                           ([gobject.TYPE_INT]))
  }
                           
  def __init__(self, widget_tree, app, fancy=False):
    gobject.GObject.__init__(self)
    self._app = app
    self._icon_manager = IconManager.IconManager(self._app.db.home)
    self._scrolled_window = widget_tree.get_widget('feed_scrolled_window')
    if utils.RUNNING_HILDON:
      hildon.hildon_helper_set_thumb_scrollbar(self._scrolled_window, True)
    self._va = self._scrolled_window.get_vadjustment()
    self._widget = widget_tree.get_widget('feedlistview')
    self._entry_list_widget = widget_tree.get_widget('entrylistview')
    
    self._feedlist = gtk.ListStore(str,            #title
                     str,            #markup title
                     int,            #feed_id
                     str,            #stockid
                     str,            #readinfo
                     gtk.gdk.Pixbuf, #pixbuf 
                     bool,           #details loaded
                     int,            #unread
                     int,            #total
                     int,            #flag
                     bool,           #visible
                     bool,           #pollfail
                     str)            #first entry title
    self._last_selected=None
    self._last_feed=None
    self.filter_setting=ALL
    self.filter_name = _("All Feeds")
    self._selecting_misfiltered=False
    self._filter_unread = False
    self._cancel_load = [False,False] #loading feeds, loading details
    self._loading_details = 0
    self._state = S_DEFAULT
    self._fancy = fancy
    self.__widget_width = 0
    self.__resetting_columns = False
    self.__displayed_context_menu = False #for hildon
    
    #build list view
    
    self._feed_filter = self._feedlist.filter_new()
    self._feed_filter.set_visible_column(VISIBLE)
    self._widget.set_model(self._feed_filter)
    
    # Icon Column
    self._icon_renderer = gtk.CellRendererPixbuf()
    self._icon_column = gtk.TreeViewColumn(_('Icon'))
    self._icon_column.pack_start(self._icon_renderer, False)
    self._icon_column.set_attributes(self._icon_renderer, stock_id=STOCKID)
    if utils.RUNNING_HILDON:
      self._icon_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    else:
      self._icon_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
      self._icon_column.set_min_width(32)
    self._widget.append_column(self._icon_column)
    
    # Feed Column
    renderer = gtk.CellRendererText()
    renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
    self._feed_column = gtk.TreeViewColumn(_('Feeds'))
    self._feed_column.pack_start(renderer, True)
    self._feed_column.set_attributes(renderer, markup=MARKUPTITLE)
    self._feed_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
    self._feed_column.set_resizable(True)
    self._feed_column.set_expand(True)
    self._widget.append_column(self._feed_column)
    
    # Articles column
    self._articles_renderer = gtk.CellRendererText()
    self._articles_column = gtk.TreeViewColumn(_(''))
    self._articles_column.set_resizable(False)
    self._articles_column.pack_start(self._articles_renderer, False)
    self._articles_column.set_attributes(self._articles_renderer, markup=READINFO)    
    self._articles_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    self._articles_column.set_expand(False)
    self._widget.append_column(self._articles_column)
    
    # Image Column
    feed_image_renderer = gtk.CellRendererPixbuf()
    self._image_column = gtk.TreeViewColumn(_('Image'))
    self._image_column.pack_start(feed_image_renderer, False)
    self._image_column.set_attributes(feed_image_renderer, pixbuf=PIXBUF)
    self._image_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
    self._image_column.set_min_width(MAX_WIDTH + 10)
    self._image_column.set_max_width(MAX_WIDTH + 10)
    self._image_column.set_expand(False)
    if self._fancy:
      self._widget.append_column(self._image_column)
    
    self.resize_columns()
    
    #signals are MANUAL ONLY
    self._widget.get_selection().connect("changed", self._item_selection_changed)
    self._widget.connect("row-activated", self.on_row_activated)
    self._widget.connect("button-press-event", self._on_button_press_event)
    self._widget.connect("button-release-event", self._on_button_release_event)
    if utils.RUNNING_HILDON:
      self._widget.tap_and_hold_setup(menu=self._get_context_menu(False))
    
    self._handlers = []
    h_id = self._app.connect('feed-polled', self.__feed_polled_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('feed-added', self.__feed_added_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('feed-removed', self.__feed_removed_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('entry-updated', self.__entry_updated_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('tags-changed', self.__tags_changed_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('state_changed', self.__state_changed_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('entries-viewed', self.__entries_viewed_cb)
    self._handlers.append((self._app.disconnect, h_id))
    h_id = self._app.connect('entries-unviewed', self.__entries_unviewed_cb)
    self._handlers.append((self._app.disconnect, h_id))
    
    #init style
    if self._fancy:
      if utils.RUNNING_SUGAR:
        self._icon_renderer.set_property('stock-size',gtk.ICON_SIZE_SMALL_TOOLBAR)
      elif utils.RUNNING_HILDON:
        self._icon_renderer.set_property('stock-size',gtk.ICON_SIZE_BUTTON)
      else:
        self._icon_renderer.set_property('stock-size',gtk.ICON_SIZE_LARGE_TOOLBAR)
      self._widget.set_property('rules-hint', True)
  
  def finalize(self):
    for disconnector, h_id in self._handlers:
      disconnector(h_id)
      
  def set_entry_view(self, entry_view):
    h_id = entry_view.connect('entries-viewed', self.__entries_viewed_cb)
    self._handlers.append((entry_view.disconnect, h_id))
      
  def __feed_polled_cb(self, app, feed_id, update_data):
    if update_data.has_key('no_changes'):
      if update_data['no_changes']:
        self.update_feed_list(feed_id, ['icon','image'], update_data)
        return
    self.update_feed_list(feed_id, ['readinfo','icon','title','image'], update_data)
    
  def __feed_added_cb(self, app, feed_id, success):
    self.update_feed_list(feed_id, ['title'])
      
  def __feed_removed_cb(self, app, feed_id):
    self.remove_feed(feed_id)
    self.resize_columns()
    
  def __tags_changed_cb(self, app, a):
    self.filter_all(False)
  
  def __entry_updated_cb(self, app, entry_id, feed_id):
    self.update_feed_list(feed_id,['readinfo','icon'])
    for f in self._app.db.get_pointer_feeds(feed_id):
      self.update_feed_list(f,['readinfo','icon'])
    
  #def __entry_selected_cb(self, feed_id, entry_id):
  #  self.mark_entries_read(feed_id, 1)
  #  

  def __entries_viewed_cb(self, app, viewlist):
    #logging.debug("feedlist entries viewed")
    for feed_id, id_list in viewlist:
      self.mark_entries_read(len(id_list), feed_id)
      
    for f in self._app.db.get_associated_feeds(feed_id):
      if f != feed_id:
        self.update_feed_list(f, ['readinfo','icon'])
    
  def __entries_unviewed_cb(self, app, viewlist):
    for feed_id, id_list in viewlist:
      self.mark_entries_read(0 - len(id_list), feed_id)
      
    for f in self._app.db.get_associated_feeds(feed_id):
      if f != feed_id:
        self.update_feed_list(f, ['readinfo','icon'])
            
  def __update_feed_count_cb(self, o, feed_id, count):
    #logging.debug("update %i ->  %i" % (feed_id, count))
    self.update_feed_list(feed_id, update_what=['readinfo'], 
      update_data={'unread_count':count})
      
    for f in self._app.db.get_associated_feeds(feed_id):
      if f != feed_id:
        self.update_feed_list(f, ['readinfo','icon'])

  def grab_focus(self):
    self._widget.grab_focus()
      
  def populate_feeds(self,callback=None, subset=ALL):
    """With 100 feeds, this is starting to get slow (2-3 seconds).  Speed helped with cache"""
    #DON'T gtk.iteration in this func! Causes endless loops!
    #if utils.RUNNING_HILDON:
    #  self._articles_column.set_visible(False)
    if len(self._feedlist)==0:
      #first fill out rough feedlist
      db_feedlist = self._app.db.get_feedlist()
      blank_pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,True,8, 10,10)
      blank_pixbuf.fill(0xffffff00)      
      for feed_id,title,url in db_feedlist:
        if utils.RUNNING_HILDON:
          title_m = '<span size="large">%s</span>' % title    
        elif self._fancy:
          title_m = title+"\n"
        else:
          title_m = title
        self._feedlist.append([title, 
                     title_m, 
                     feed_id, 
                     'gtk-stock-blank', 
                     "", 
                     blank_pixbuf, 
                     False,
                     0, 
                     0, 
                     0, 
                     False, 
                     False,
                     ""]) #assume invisible
    self.filter_all(False)
    gobject.idle_add(self._update_feeds_generator(callback,subset).next)
    #self._update_feeds_generator(subset)
    return False #in case this was called by the timeout below
    
  def _update_feeds_generator(self, callback=None, subset=ALL):
    """A generator that updates the feed list.  Called from populate_feeds"""  
    selection = self._widget.get_selection()
    #selected = self.get_selected()
    feed_cache = self._app.db.get_feed_cache()
    db_feedlist = self._app.db.get_feedlist()
    
    blank_pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,True,8, 10,10)
    blank_pixbuf.fill(0xffffff00)
    
    # While populating, allow articles column to autosize
    #self._articles_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    self._articles_column.set_min_width(50)
    
    self._feed_column.set_resizable(False)
    self._feed_column.set_expand(False)
    self._feed_column.set_min_width(self._feed_column.get_width())
    
    # create a sorted list of feedids with the visible ones first
    # if not ALL, then we don't sort and it's all fine
    i=-1
    loadlist = []
    for f in self._feedlist:
      i+=1
      loadlist.append((not f[VISIBLE], i))
    if subset == ALL:
      loadlist.sort()
      
    j=-1
    for vis, i in loadlist:
      feed_id,title,url = db_feedlist[i]
      if self._cancel_load[0]:
        break
      j+=1
      
      if subset==DOWNLOADED:
        flag = self._feedlist[i][FLAG]
        if flag & ptvDB.F_DOWNLOADED==0 and flag & ptvDB.F_PAUSED==0:
          print "not downloaded and not paused, skipping"
          continue
      elif subset==VISIBLE:
        if not self._feedlist[i][VISIBLE]:
          continue
      elif subset==NOTVISIBLE:
        if self._feedlist[i][VISIBLE]:
          continue
      
      if feed_cache is not None:
        try:
          cached     = feed_cache[i]
          flag       = cached[1]
          unviewed   = cached[2]
          entry_count= cached[3]
          pollfail   = cached[4]
          m_first_entry_title = cached[5]
        except:
          #bad cache, trigger test below
          entry_count = None
      else:
        feed_info   = self._app.db.get_feed_verbose(feed_id)
        unviewed    = feed_info['unread_count']
        flag        = feed_info['important_flag']
        pollfail    = feed_info['poll_fail']
        entry_count = feed_info['entry_count']
        m_first_entry_title = ""
      if entry_count==0 or entry_count is None: #this is a good indication that the cache is bad
        feed_info   = self._app.db.get_feed_verbose(feed_id)
        unviewed    = feed_info['unread_count']
        flag        = feed_info['important_flag']
        pollfail    = feed_info['poll_fail']
        entry_count = feed_info['entry_count']
        m_first_entry_title = ""
        
      if self._feedlist[i][FLAG]!=0:
        flag = self._feedlist[i][FLAG] #don't overwrite flag (race condition)
        
      if unviewed == 0 and flag & ptvDB.F_UNVIEWED:
        print "WARNING: zero unread articles but flag says there should be some"
        flag -= ptvDB.F_UNVIEWED
        
      if self.filter_setting == DOWNLOADED:
        visible = bool(flag & ptvDB.F_DOWNLOADED)
      else:
        visible = self._feedlist[i][VISIBLE]
      
      if self._fancy:
        if visible:
          if len(m_first_entry_title) == 0:
            m_first_entry_title = self._app.db.get_first_entry_title(feed_id, True)
          m_details_loaded = True
        else:
          if len(m_first_entry_title) > 0:
            m_details_loaded = True
          else:
            m_details_loaded = False
        if utils.RUNNING_HILDON:
          m_pixbuf = self._icon_manager.get_icon_pixbuf(feed_id , 
                    64, 64, MIN_SIZE, MIN_SIZE)  
        else:
          m_pixbuf = self._icon_manager.get_icon_pixbuf(feed_id) #, 
                    #MAX_WIDTH, MAX_HEIGHT, MIN_SIZE, MIN_SIZE)
        model, iter = selection.get_selected()
        try: sel = model[iter][FEEDID]
        except: sel = -1
        m_title = self._get_fancy_markedup_title(title,m_first_entry_title,unviewed,entry_count,flag,feed_id)
        m_readinfo = self._get_markedup_title("(%d/%d)\n" % (unviewed,entry_count), flag)
      else:
        m_title = self._get_markedup_title(title,flag)
        if utils.RUNNING_HILDON:
          m_readinfo = self._get_markedup_title("(%d)" % (unviewed), flag)
        else:
          m_readinfo = self._get_markedup_title("(%d/%d)" % (unviewed,entry_count), flag)
        m_pixbuf = blank_pixbuf
        m_first_entry_title = ""
        m_details_loaded = False
        
      icon = self._get_icon(flag)  
      
      if pollfail:
         if icon=='gtk-harddisk' or icon=='gnome-stock-blank':
           icon='gtk-dialog-error'
      
      self._feedlist[i] = [title, 
                 m_title, 
                 feed_id, 
                 icon, 
                 m_readinfo, 
                 m_pixbuf, 
                 m_details_loaded, 
                 unviewed, 
                 entry_count, 
                 flag, 
                 visible, 
                 pollfail, 
                 m_first_entry_title]
      if self.filter_setting == DOWNLOADED and visible:  
        self._feed_filter.refilter()      

      self._app.main_window.update_progress_bar(float(j)/len(db_feedlist),MainWindow.U_LOADING)
      yield True
    self._app.main_window.update_progress_bar(-1,MainWindow.U_LOADING)
    # Once we are done populating, set size to fixed, otherwise we get
    # a nasty flicker when we click on feeds
    self.resize_columns()
    
    if self._fancy:
      gobject.timeout_add(500, self._load_details(visible_only=False).next)
    
    if not self._cancel_load[0]:
      if self._fancy:
        gobject.idle_add(self._load_details().next)
      #if selected:
      #  self.set_selected(selected)
      if callback is not None:
        try: callback()
        except: pass
    else:
      self._cancel_load[0] = False
    yield False
    
  def resize_columns(self):
    self._reset_articles_column()
    
  def _reset_articles_column(self, harsh=False):
    #temporarily allow articles column to size itself, then set it
    #to fixed again to avoid flicker.
    
    #don't allow us to resize twice in a row (before idle_add can act)
    if self.__resetting_columns:
      return
    self.__resetting_columns = True
      
    self._articles_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    self._articles_column.set_min_width(50)
    self._feed_column.set_resizable(True)
    self._feed_column.set_expand(True)
    self._feed_column.set_min_width(0)
    self._widget.columns_autosize()
    
    def _finish_resize():
      self._articles_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
      self._articles_column.set_min_width(self._articles_column.get_width())
      self.__resetting_columns = False
      return False
      
    gobject.idle_add(_finish_resize)
    
  def update_feed_list(self, feed_id=None, update_what=None, update_data=None, recur_ok=True):  #returns True if this is the already-displayed feed
    """updates the feed list.  Right now uses db to get flags, entrylist (for unread count), pollfail
  
    We should just get the flag, unread count, and poll fail, and then figure out:
       icon, markup, and numbers
       
    update_data would be a dic with unreadcount, flag list, and pollfail
    
    update_what is a bunch of strings saying what we want to update.  it will go to the
    db for info unless the value is already in update_data"""
    
    #logging.debug("updating feed list: %s", str(update_what))
    
    if feed_id is None:
      if self._last_feed is None:
        return
      feed_id = self._feedlist[self._last_feed][FEEDID]
      
    if update_what is None:
      update_what = ['readinfo','icon','title']
    if update_data is None:
      update_data = {}
      
    if 'readinfo' in update_what and 'title' not in update_what:
      update_what.append('title') #need this too
    
    try:
      feed = self._feedlist[self.find_index_of_item(feed_id)]
    except:
      logging.warning("tried to update feed not in list: %i, %s, %s, %s" % (feed_id, str(update_what), str(update_data), str(recur_ok)))
      return
      
    need_filter = False #some updates will require refiltering. 
    need_resize = False
    
    if update_what == ['icon'] and update_data.has_key('icon'):
      #FIXME: hack for download notification
      feed[STOCKID] = update_data['icon']
      return
    
    if 'title' in update_what or 'icon' in update_what:
      if not update_data.has_key('flag_list'):
        update_data['flag_list'] = self._app.db.get_entry_flags(feed_id)
            
      updated=0
      unviewed=0
      downloaded=0
       
      for flag in update_data['flag_list']:
        if flag & ptvDB.F_UNVIEWED == ptvDB.F_UNVIEWED:
          unviewed=unviewed+1
        if flag & ptvDB.F_DOWNLOADED or flag & ptvDB.F_PAUSED:
          downloaded=1        
      flag = self._pick_important_flag(feed_id, update_data['flag_list'])        

    if 'image' in update_what and self._fancy:
      if utils.RUNNING_HILDON:
        feed[PIXBUF] = self._icon_manager.get_icon_pixbuf(feed_id, 
              64, 64, MIN_SIZE, MIN_SIZE)
      else:
        feed[PIXBUF] = self._icon_manager.get_icon_pixbuf(feed_id) #, 
              #MAX_WIDTH, MAX_HEIGHT, MIN_SIZE, MIN_SIZE)
      
    if 'readinfo' in update_what:
      #db_unread_count = self._app.db.get_unread_count(feed_id) #need it always for FIXME below
      if not update_data.has_key('unread_count'):
        update_data['unread_count'] = self._app.db.get_unread_count(feed_id)#, db_unread_count)
      if update_data['unread_count'] > 0:
        if feed[FLAG] & ptvDB.F_UNVIEWED==0:
          feed[FLAG] = feed[FLAG] + ptvDB.F_UNVIEWED
      else:
        if feed[FLAG] & ptvDB.F_UNVIEWED:
          feed[FLAG] = feed[FLAG] - ptvDB.F_UNVIEWED
      feed[UNREAD]   = update_data['unread_count']
      feed[TOTAL]    = len(update_data['flag_list'])

      if utils.RUNNING_HILDON and not self._fancy:
        readinfo_string = "(%d)" % (update_data['unread_count'],)
      else:
        readinfo_string = "(%d/%d)" % (update_data['unread_count'], len(update_data['flag_list']))
      if self._fancy:
        readinfo_string += "\n"
      if readinfo_string != feed[READINFO]:
        feed[READINFO] = self._get_markedup_title(readinfo_string,flag)
        #print feed[MARKUPTITLE], feed[READINFO]
        need_resize = True
      
      if self._filter_unread:
        if self.filter_test_feed(feed_id): #no sense testing the filter if we won't see it
          need_filter = True
        
    if 'title' in update_what:
      selected = self.get_selected()
      if not update_data.has_key('title'):
        update_data['title'] = self._app.db.get_feed_title(feed_id)
      old_title_len = len(feed[TITLE])
      new_title_len = len(update_data['title'])
      
      # don't update feed[TITLE] yet, we need these data first
      if self._fancy:
        try: feed[FIRSTENTRYTITLE] = self._app.db.get_first_entry_title(feed_id, True)
        except: feed[FIRSTENTRYTITLE] = ""
        feed[MARKUPTITLE] = self._get_fancy_markedup_title(update_data['title'],feed[FIRSTENTRYTITLE],feed[UNREAD], feed[TOTAL], flag, feed[FEEDID])
      else:
        feed[MARKUPTITLE] = self._get_markedup_title(update_data['title'], flag)
        
      if feed[TITLE] != update_data['title']:
        feed[TITLE] = update_data['title']
        try:
          old_iter = self._feedlist.get_iter((self.find_index_of_item(feed_id),))
          new_iter = self._feedlist.get_iter(([f[0] for f in self._app.db.get_feedlist()].index(feed_id),))
          self._feedlist.move_after(old_iter,new_iter)
          if selected == feed_id:
            self._widget.scroll_to_cell((self.find_index_of_item(feed_id),))
        except:
          print "Error finding feed for update"
        need_filter = True
        #columns_autosize produces a flicker, so only do it if we need to
        if abs(new_title_len - old_title_len) > 5:
          need_resize = True
          #self.resize_columns()
      
    if 'icon' in update_what:
      if not update_data.has_key('pollfail'):
        update_data['pollfail'] = self._app.db.get_feed_poll_fail(feed_id)
      feed[POLLFAIL] = update_data['pollfail']
      feed[STOCKID] = self._get_icon(flag)
      if update_data['pollfail']:
        #print update_data
        if feed[STOCKID]=='gtk-harddisk' or feed[STOCKID]=='gnome-stock-blank':
          feed[STOCKID]='gtk-dialog-error'
      feed[FLAG] = flag   
       if self.filter_setting == DOWNLOADED:
         if downloaded==0:
           need_filter = True  
      
    if need_filter and self._state != S_SEARCH:#not self._showing_search:
      self._filter_one(feed)
      
    if need_resize:
      self.resize_columns()
      
  def mark_entries_read(self, num_to_mark, feed_id=None):
  
    """alters the number of unread entries by num_to_mark.  if negative,
    marks some as unread"""
    
    #there's some trickiness here.  The model for the selection is
    #self._feed_filter, not self._feedlist, so we can't write to items
    #in that model.  We have to go back and find where this feed is in the
    #original model.
    
    if feed_id is None:
      s = self._widget.get_selection().get_selected()
      if s is None:
        return
      model, iter = s
      if iter is None:
        return

      unfiltered_iter = model.convert_iter_to_child_iter(iter)
      feed = self._feedlist[unfiltered_iter]
    else:
      feed = self._feedlist[self.find_index_of_item(feed_id)]

    #sanity check
    if feed[UNREAD] - num_to_mark < 0 or feed[UNREAD] - num_to_mark > feed[TOTAL]:
      print "WARNING: trying to mark more or less than we have:", feed[TITLE], feed[UNREAD], num_to_mark
      print feed[UNREAD],feed[TOTAL],num_to_mark
      self.update_feed_list(feed[FEEDID], ['readinfo'])
      return
      
    feed[UNREAD] -= num_to_mark
    
    if feed[UNREAD] == 0 and feed[FLAG] & ptvDB.F_UNVIEWED:
      feed[FLAG] -= ptvDB.F_UNVIEWED
      
    if feed[UNREAD] > 0 and feed[FLAG] & ptvDB.F_UNVIEWED == 0:
      feed[FLAG] += ptvDB.F_UNVIEWED
    
    if utils.RUNNING_HILDON and not self._fancy:
      readinfo_string = "(%d)" % (feed[UNREAD],)
    else:
      readinfo_string = "(%d/%d)" % (feed[UNREAD], feed[TOTAL])
    
    if self._fancy:
      readinfo_string += "\n"
      feed[MARKUPTITLE] = self._get_fancy_markedup_title(feed[TITLE],
                                 feed[FIRSTENTRYTITLE],
                                 feed[UNREAD], 
                                 feed[TOTAL], 
                                 feed[FLAG], 
                                 feed[FEEDID])
    else:
      feed[MARKUPTITLE] = self._get_markedup_title(feed[TITLE], feed[FLAG])
      
    feed[READINFO] = self._get_markedup_title(readinfo_string,feed[FLAG])
    
    if self._filter_unread:    
      self._filter_one(feed)
        
  def show_search_results(self, results=[]):
    
    """shows the feeds in the list 'results'"""
    
    if self._state != S_SEARCH:
      print "not in search state, returning"
      return
      
    if self._last_feed is not None:
      old_item = self._feedlist[self._last_feed]
      old_item[MARKUPTITLE] = self._get_fancy_markedup_title(old_item[TITLE],old_item[FIRSTENTRYTITLE],old_item[UNREAD], old_item[TOTAL], old_item[FLAG], old_item[FEEDID])
      
    if results is None:
      results = []
    #print results[0]
    if len(results) == 0:
      for feed in self._feedlist:
        feed[VISIBLE] = 0
      self._feed_filter.refilter()
      return
    
    for feed in self._feedlist:
      if feed[FEEDID] in results:
        feed[VISIBLE] = 1
      else:
        feed[VISIBLE] = 0
              
    id_list = [feed[FEEDID] for feed in self._feedlist]
            
    def sorter(a, b):
      if a[VISIBLE] != b[VISIBLE]:
        return b[VISIBLE] - a[VISIBLE]
      if a[VISIBLE]==1:
        return results.index(a[FEEDID]) - results.index(b[FEEDID])
      else:
        return id_list.index(a[FEEDID]) - id_list.index(b[FEEDID])
    
    #convert to list
    f_list = list(self._feedlist)
    #we sort the new feed list as is
    f_list.sort(sorter)
    #we go through the new feed list, and for each id find its old index
    i_list = []
    for f in f_list:
      i_list.append(id_list.index(f[FEEDID]))
    #we now have a list of old indexes in the new order    
    self._feedlist.reorder(i_list)
    self._feed_filter.refilter()
    if self._fancy:
      gobject.idle_add(self._load_details().next)
    self._va.set_value(0)
    self._widget.get_selection().unselect_all()
    
  def _unset_state(self, data=True):
    if self._state == S_SEARCH:
      gonna_filter = data
      showing_feed = self.get_selected()
      id_list = [feed[FEEDID] for feed in self._feedlist]
      f_list = list(self._feedlist)
      def alpha_sorter(x,y):
        if x[TITLE].upper()>y[TITLE].upper():
          return 1
        if x[TITLE].upper()==y[TITLE].upper():
          return 0
        return -1
      f_list.sort(alpha_sorter)
      i_list = []
      for f in f_list:
        i_list.append(id_list.index(f[FEEDID]))
      self._feedlist.reorder(i_list)
      if showing_feed is not None:
        #self._app.display_feed(showing_feed)
        self.emit('feed-selected', showing_feed)
        if not self.filter_test_feed(showing_feed):
          self._app.main_window.set_active_filter(ALL)
        self.set_selected(showing_feed)
      elif gonna_filter == False:
        self._app.main_window.set_active_filter(ALL)
        #self._app.display_entry(None)
        self.emit('no-feed-selected')

  
  def __state_changed_cb(self, app, newstate, data=None):
    d = {penguintv.DEFAULT: S_DEFAULT,
       penguintv.MANUAL_SEARCH: S_SEARCH,
       penguintv.TAG_SEARCH: S_SEARCH,
       penguintv.MAJOR_DB_OPERATION: S_MAJOR_DB_OPERATION}
       
    newstate = d[newstate]
    
    if newstate == self._state:
      return
       
    self._unset_state(data)
    self._state = newstate
      
  def filter_all(self, keep_misfiltered=True):
    if utils.HAS_SEARCH and self.filter_setting == SEARCH:
      print "not filtering, we have search results"
      return False#not my job
      
    #gtk.gdk.threads_enter()
    selected = self.get_selected()
    index = self.find_index_of_item(selected)
    
    #stupid exception for when we don't have search
    if self.filter_setting > SEARCH:# or (not utils.HAS_SEARCH and self.filter_setting == SEARCH):
      feeds_with_tag = self._app.db.get_feeds_for_tag(self.filter_name)
      
    i=-1
    for feed in self._feedlist:
      i=i+1
      flag = feed[FLAG]
      passed_filter = False
      
      if self.filter_setting == DOWNLOADED:
        if flag & ptvDB.F_DOWNLOADED or flag & ptvDB.F_PAUSED:
          passed_filter = True
      elif self.filter_setting == NOTIFY:
        opts = self._app.db.get_flags_for_feed(feed[FEEDID])
        if opts & ptvDB.FF_NOTIFYUPDATES:
          passed_filter = True
      elif self.filter_setting == ALL:
        passed_filter = True
      else:
        #tags = self._app.db.get_tags_for_feed(feed[FEEDID])
        #if tags:
        #  if self.filter_name in tags:
        #    passed_filter = True
        if feed[FEEDID] in feeds_with_tag:
          passed_filter = True
      #so now we know if we passed the main filter, but we need to test for special cases where we keep it anyway
      #also, we still need to test for unviewed
      if i == index and selected is not None:  #if it's the selected feed, we have to be careful
        if keep_misfiltered: 
          #some cases when we want to keep the current feed visible
          if self._filter_unread == True and flag & ptvDB.F_UNVIEWED==0: #if it still fails the unviewed test
            passed_filter = True  #keep it
            self._selecting_misfiltered=True
          elif self.filter_setting == DOWNLOADED and flag & ptvDB.F_DOWNLOADED == 0 and flag & ptvDB.F_PAUSED == 0:
            passed_filter = True
            self._selecting_misfiltered=True
          elif self.filter_setting == DOWNLOADED and flag & ptvDB.F_DOWNLOADING:
            passed_filter = True
            self._selecting_misfiltered=True
        if not passed_filter:
          self._widget.get_selection().unselect_all() #and clear out the entry list and entry view
          if self._fancy:
            feed[MARKUPTITLE] = self._get_fancy_markedup_title(feed[TITLE],feed[FIRSTENTRYTITLE],feed[UNREAD], feed[TOTAL], feed[FLAG], feed[FEEDID])
          #self._app.display_feed(-1)
          self.emit('no-feed-selected')
      else: #if it's not the selected feed
        if self._filter_unread == True and flag & ptvDB.F_UNVIEWED==0: #and it fails unviewed
          passed_filter = False #see ya
      if feed[VISIBLE] != passed_filter:
        feed[VISIBLE] = passed_filter #note, this seems to change the selection!
    self._feed_filter.refilter()
    self.resize_columns()
    #gtk.gdk.threads_leave()
    return False

  def _filter_one(self,feed, keep_misfiltered=True):
    if utils.HAS_SEARCH and self.filter_setting == SEARCH:
      print "not filtering, we have search results"
      return #not my job
  
    selected = self.get_selected()
    s_index = self.find_index_of_item(selected)
    feed_index = self.find_index_of_item(feed[FEEDID])
    
    flag = feed[FLAG]
    passed_filter = False
    
    if self.filter_setting == DOWNLOADED:
      if flag & ptvDB.F_DOWNLOADED or flag & ptvDB.F_PAUSED:
        passed_filter = True
    elif self.filter_setting == NOTIFY:
      opts = self._app.db.get_flags_for_feed(feed[FEEDID])
      if opts & ptvDB.FF_NOTIFYUPDATES:
        passed_filter = True
    elif self.filter_setting == ALL:
      passed_filter = True
    else:
      tags = self._app.db.get_tags_for_feed(feed[FEEDID])
      if tags:
        if self.filter_name in tags:
          passed_filter = True
    #so now we know if we passed the main filter, but we need to test for special cases where we keep it anyway
    #also, we still need to test for unviewed
    if feed_index == s_index and selected is not None:  #if it's the selected feed, we have to be careful
      if keep_misfiltered: 
        #some cases when we want to keep the current feed visible
        if self._filter_unread == True and flag & ptvDB.F_UNVIEWED==0: #if it still fails the unviewed test
          passed_filter = True  #keep it
          self._selecting_misfiltered=True
        elif self.filter_setting == DOWNLOADED and flag & ptvDB.F_DOWNLOADED == 0 and flag & ptvDB.F_PAUSED == 0:
          passed_filter = True
          self._selecting_misfiltered=True
        elif self.filter_setting == DOWNLOADED and flag & ptvDB.F_DOWNLOADING:
          passed_filter = True
          self._selecting_misfiltered=True
      if not passed_filter:
        self._widget.get_selection().unselect_all() #and clear out the entry list and entry view
        #self._app.display_feed(-1)
        self.emit('no-feed-selected')
    else: #if it's not the selected feed
      if self._filter_unread == True and flag & ptvDB.F_UNVIEWED==0: #and it fails unviewed
        passed_filter = False #see ya
    if feed[VISIBLE] != passed_filter:
      feed[VISIBLE] = passed_filter #note, this seems to change the selection!
    self._feed_filter.refilter()
      
  def _load_details(self, visible_only=True):
    if visible_only:
      if self._loading_details == 1:
        yield False
      self._loading_details = 1
    else:
      if self._loading_details > 0:
        yield False
      self._loading_details = 2
      
    for row in self._feedlist:
      if self._cancel_load[1]:
        break
      if not visible_only and self._loading_details == 1:
        break

      if (row[VISIBLE] or not visible_only) and not row[DETAILS_LOADED]:
        then = time.time()
        try: row[FIRSTENTRYTITLE] = self._app.db.get_first_entry_title(row[FEEDID], True)
        except: row[FIRSTENTRYTITLE] = ""
        now = time.time()
        if now - then > 2 and not visible_only:
          #print "too slow, quit"
          break
        #row[PIXBUF] = self._get_pixbuf(row[FEEDID])
        model, iter = self._widget.get_selection().get_selected()
        row[DETAILS_LOADED] = True
        try: selected = model[iter][FEEDID]
        except: selected = -1
        row[MARKUPTITLE] = self._get_fancy_markedup_title(row[TITLE],
                                  row[FIRSTENTRYTITLE],
                                  row[UNREAD],
                                  row[TOTAL],
                                  row[FLAG],
                                  row[FEEDID])
        #self.resize_columns()
        yield True
    if self._cancel_load[1]:
      self._cancel_load[1] = False

    self._loading_details = 0
    if visible_only and len(self._feedlist) > 0 and self._fancy:
      #print "now loading everything else"
      gobject.timeout_add(500, self._load_details(visible_only=False).next)
        
    yield False
        
  def filter_test_feed(self, feed_id):
    """Tests a feed against the filters (although _not_ unviewed status testing)"""
    passed_filter = False
    try:
      flag = self._feedlist[self.find_index_of_item(feed_id)][FLAG]
    except:
      return False
    
    if self.filter_setting == DOWNLOADED:
      if flag & ptvDB.F_DOWNLOADED or flag & ptvDB.F_PAUSED:
        passed_filter = True
    elif self.filter_setting == NOTIFY:
      opts = self._app.db.get_flags_for_feed(feed[FEEDID])
      if opts & ptvDB.FF_NOTIFYUPDATES:
        passed_filter = True
    elif self.filter_setting == ALL:
      passed_filter = True
    else:
      tags = self._app.db.get_tags_for_feed(feed_id)
      if tags:
        if self.filter_name in tags:
          passed_filter = True
    return passed_filter
      
  def on_row_activated(self, treeview, path, view_column):
    if utils.RUNNING_HILDON:
      #much too easy to doubleclick on hildon, disable
      return
    index = path[0]
    model = treeview.get_model()
    link = self._app.db.get_feed_info(model[index][FEEDID])['link']
    if link is None:
      dialog = gtk.Dialog(title=_("No Homepage"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
      label = gtk.Label(_("There is no homepage associated with this feed.  You can set one in the feed properties."))
      dialog.vbox.pack_start(label, True, True, 0)
      label.show()
      dialog.run()
      dialog.hide()
      del dialog
    #self._app.activate_link(link)
    self.emit('link-activated', link)
    
  def set_filter(self, new_filter, name):
    self.filter_setting = new_filter
    self.filter_name = name

    #if new_filter != SEARCH and self._state == S_SEARCH:
    #  print "hope we also changed state"
    #  self._app.set_state(penguintv.DEFAULT)
      
    self.filter_all(False)
    if self._fancy:
      gobject.idle_add(self._load_details().next)
    self._va.set_value(0)
    self.resize_columns()
    
  def set_fancy(self, fancy):
    if fancy == self._fancy:
      return #no need
    if self._state == S_MAJOR_DB_OPERATION:
      self.interrupt()
      while gtk.events_pending():
        gtk.main_iteration()
    #self._app.set_state(penguintv.MAJOR_DB_OPERATION)
    self.emit('state-change', penguintv.MAJOR_DB_OPERATION)
    self._fancy = fancy
    if self._fancy:
      self._widget.append_column(self._image_column)
      self._icon_renderer.set_property('stock-size',gtk.ICON_SIZE_LARGE_TOOLBAR)
      self._widget.set_property('rules-hint', True)
    else:
      self._widget.remove_column(self._image_column)
      self._icon_renderer.set_property('stock-size',gtk.ICON_SIZE_SMALL_TOOLBAR)
      self._widget.set_property('rules-hint', False)
    if self._state == S_SEARCH:
      #self._app.set_state(penguintv.DEFAULT)
      self.emit('state-change', penguintv.DEFAULT)
    self._app.write_feed_cache()
    self.clear_list()
    self.populate_feeds(self._app._done_populating)
    self.resize_columns()
    
  def set_unread_toggle(self, active):
    if self._state == S_SEARCH:
      return 
    self._filter_unread = active
    self.filter_all(False)
    if self._fancy:
      gobject.idle_add(self._load_details().next)
    self._va.set_value(0)  
    
  def clear_list(self):
    self._feedlist.clear()
    
  def add_feed(self, feed_id):
    newlist = self._app.db.get_feedlist()
    index = [f[0] for f in newlist].index(feed_id)
    feed = newlist[index]
    #print "-----------ADDFEED---------"
    #print feed
    #print index
    #print newlist
    p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,True,8, 10,10)
    p.fill(0xffffff00)
    #insert, not append
    self._feedlist.insert(index,[feed[1], feed[1], feed[0], 'gnome-stock-blank', "", p, False, 1, 1, 0, True, False, ""])
    self.update_feed_list(feed_id)
    
  def remove_feed(self, feed_id):
    try:
      if feed_id == self._feedlist[self._last_feed][FEEDID]:
        self._last_feed = None
      self._feedlist.remove(self._feedlist.get_iter((self.find_index_of_item(feed_id),)))
    except:
      print "Error: feed not in list"
      
  def _on_button_press_event(self, widget, event):
    if event.button==3: #right click
      self.do_context_menu(widget, event)
      
  def _on_button_release_event(self, widget, event):
    if self.__displayed_context_menu:
      self.__displayed_context_menu = False
      return
    if event.button==1:
      self.emit('feed-clicked')
      
  def _get_context_menu(self, is_filter):
    menu = gtk.Menu()
    
    if is_filter and not utils.HAS_SEARCH:
      item = gtk.MenuItem(_("Search required for feed filters"))
      item.set_sensitive(False)
      menu.append(item)
      separator = gtk.SeparatorMenuItem()
      menu.append(separator)

    item = gtk.ImageMenuItem('gtk-refresh')
    item.connect('activate',self._app.main_window.on_refresh_activate)
    if is_filter and not utils.HAS_SEARCH:
      item.set_sensitive(False)
    menu.append(item)
  
    item = gtk.MenuItem(_("Mark as _Viewed"))
    item.connect('activate',self._app.main_window.on_mark_feed_as_viewed_activate)
    if is_filter and not utils.HAS_SEARCH:
      item.set_sensitive(False)
    menu.append(item)
  
    item = gtk.MenuItem(_("_Delete All Media"))
    item.connect('activate',self._app.main_window.on_delete_feed_media_activate)
    if is_filter and not utils.HAS_SEARCH:
      item.set_sensitive(False)
    menu.append(item)
  
    item = gtk.ImageMenuItem(_("_Remove Feed"))
    img = gtk.image_new_from_stock('gtk-remove',gtk.ICON_SIZE_MENU)
    item.set_image(img)
    item.connect('activate',self._app.main_window.on_remove_feed_activate)
    if self._state == S_MAJOR_DB_OPERATION:
      item.set_sensitive(False)
    menu.append(item)

  
    separator = gtk.SeparatorMenuItem()
    menu.append(separator)
  
    if not is_filter:
      if utils.HAS_SEARCH:
        item = gtk.MenuItem(_("_Create Feed Filter"))
        item.connect('activate',self._app.main_window.on_add_feed_filter_activate)
        if self._state == S_MAJOR_DB_OPERATION:
          item.set_sensitive(False)
        menu.append(item)
    
      item = gtk.ImageMenuItem('gtk-properties')
      item.connect('activate',self._app.main_window.on_feed_properties_activate)
      menu.append(item)
    else:
      item = gtk.ImageMenuItem('gtk-properties')
      item.connect('activate',self._app.main_window.on_feed_filter_properties_activate)
      if not utils.HAS_SEARCH:
        item.set_sensitive(False)
      menu.append(item)
    
    menu.show_all()
    def realized(o):
      self.__displayed_context_menu = True
    menu.connect('realize', realized)
    return menu

  def do_context_menu(self, widget, event):
    path = widget.get_path_at_pos(int(event.x),int(event.y))
    model = widget.get_model()
    if path is None: #nothing selected
      return
    selected = model[path[0]][FEEDID]
    is_filter = self._app.db.is_feed_filter(selected)  

    menu = self._get_context_menu(is_filter)

    menu.popup(None,None,None, event.button,event.time)
        
  def _get_icon(self, flag):
    if flag & ptvDB.F_ERROR == ptvDB.F_ERROR:
      return 'gtk-dialog-error'
    if flag & ptvDB.F_DOWNLOADING == ptvDB.F_DOWNLOADING:
      return 'gtk-execute'
    if flag & ptvDB.F_DOWNLOADED == ptvDB.F_DOWNLOADED:
      return 'gtk-harddisk'
    if flag & ptvDB.F_PAUSED:
      return 'gtk-media-pause'
    return 'gnome-stock-blank'
  
  def _get_markedup_title(self, title, flag):
    if not title:
      return _("Please wait...")
    if utils.RUNNING_SUGAR:
      title='<span size="x-small">'+title+'</span>'
    elif utils.RUNNING_HILDON:
      title='<span size="large">'+title+'</span>'
    try:
      if flag & ptvDB.F_UNVIEWED == ptvDB.F_UNVIEWED:
          title="<b>"+utils.my_quote(title)+"</b>"
    except:
      return title
    return title
    
  def _get_fancy_markedup_title(self, title, first_entry_title, unread, total, flag, feed_id, selected=None):
    #logging.debug("fancy title: %s %s %i %i %i %i", title, first_entry_title, unread, total, flag, feed_id)
    if selected is None:
      selection = self._widget.get_selection()
      model, iter = selection.get_selected()
      try: sel = model[iter][FEEDID]
      except: sel = -1
      selected = feed_id == sel
      
    if not title:
      return _("Please wait...")
    try:
      if utils.RUNNING_HILDON:
        if not selected:
          title = '<span size="large">'+utils.my_quote(title)+'</span>\n<span color="#777777"><i>'+utils.my_quote(first_entry_title)+'</i></span>'
        else:
          title = '<span size="large">'+utils.my_quote(title)+'</span>\n<span><i>'+utils.my_quote(first_entry_title)+'</i></span>'
      else:
        if not selected:
          title = utils.my_quote(title)+'\n<span color="#777777" size="x-small"><i>'+utils.my_quote(first_entry_title)+'</i></span>'
        else:
          title = utils.my_quote(title)+'\n<span size="x-small"><i>'+utils.my_quote(first_entry_title)+'</i></span>'  
      
      if flag & ptvDB.F_UNVIEWED == ptvDB.F_UNVIEWED:
        if unread == 0:
          logging.warning("Flag says there are unviewed, but count says no.  not setting bold")
        else:
          title="<b>"+title+'</b>'
    except:
      return title
    return title
  
  def _pick_important_flag(self, feed_id, flag_list):
    """go through entries and pull out most important flag"""
    if len(flag_list)==0:
      return 0

    entry_count = len(flag_list)
    important_flag = 0
    media_exists = 0
    for flag in flag_list:
      if flag & ptvDB.F_DOWNLOADED == ptvDB.F_DOWNLOADED:
        media_exists=1
        break
    flag_list.sort()
    best_flag = flag_list[-1]
    if best_flag & ptvDB.F_DOWNLOADED == 0 and media_exists==1: #if there is an unread text-only entry, but all viewed media,
                                  #we need a special case (mixing flags from different entries)
      return best_flag + ptvDB.F_DOWNLOADED
    else:
      return best_flag
      
  def _item_selection_changed(self, selection):
    if self._fancy and self._last_feed is not None:
      try: 
        old_item = self._feedlist[self._last_feed]
        old_item[MARKUPTITLE] = self._get_fancy_markedup_title(old_item[TITLE],old_item[FIRSTENTRYTITLE],old_item[UNREAD], old_item[TOTAL], old_item[FLAG], old_item[FEEDID], False)
      except:
        pass
        
    s = selection.get_selected()
    if s:
      model, iter = s
      if iter is None:
        self.emit('no-feed-selected') 
        return
      unfiltered_iter = model.convert_iter_to_child_iter(iter)
      feed = self._feedlist[unfiltered_iter]
    else:
      self.emit('no-feed-selected') 
      return
      
    self._last_feed=unfiltered_iter
    self._select_after_load=None
    
    if self._fancy:
      feed[MARKUPTITLE] = self._get_fancy_markedup_title(feed[TITLE],feed[FIRSTENTRYTITLE],feed[UNREAD], feed[TOTAL], feed[FLAG], feed[FEEDID], True)

    try:
      if self._feedlist[self.find_index_of_item(feed[FEEDID])][POLLFAIL]:
        self._app.display_custom_entry("<b>"+_("There was an error trying to poll this feed.")+"</b>")
      else:
        self._app.undisplay_custom_entry()
    except:
      self._app.undisplay_custom_entry()

    #if self._showing_search:
    if self._state == S_SEARCH:
      if feed[FEEDID] == self._last_selected:
        return
      self._last_selected = feed[FEEDID]
      if not self._app.entrylist_selecting_right_now():
        self.emit('search-feed-selected', feed[FEEDID])
      return
    if feed[FEEDID] == self._last_selected:
      self.emit('feed-selected', feed[FEEDID])
    else:
      self._last_selected = feed[FEEDID]
      self.emit('feed-selected', feed[FEEDID])
      if self._selecting_misfiltered and feed[FEEDID]!=None:
        self._selecting_misfiltered = False
        gobject.timeout_add(250, self.filter_all)
      
  def get_selected(self, selection=None):
    if selection==None:
      try:
        s = self._widget.get_selection().get_selected()
      except AttributeError:
        return None
    else:
      s = selection.get_selected()
    if s:
      model, iter = s
      if iter is None:
        return None
      path = model.get_path(iter)
      index = path[0]
      return model[index][FEEDID]
    else:
      return None
      
  def set_selected(self, feed_id):
    if feed_id is None:
      self._widget.get_selection().unselect_all()
      return
    visible = [f[FEEDID] for f in self._feedlist if f[VISIBLE]]
    index=None
    try:
      index = visible.index(feed_id)
    except:
      pass
    if index is None:
      if self.filter_setting != ALL:
        self._app.main_window.set_active_filter(ALL) #hmm..
        self.set_selected(feed_id)
        return
      else:
        self._widget.get_selection().unselect_all()
    else:
      #FIXME: why are we crashing here sometimes???
      self._widget.get_selection().select_path((index,))
      self._widget.scroll_to_cell((index,))
      
  def find_index_of_item(self, feed_id):
    try:
      i=-1
      for feed in self._feedlist:
        i+=1
        if feed_id == feed[FEEDID]:
          return i
      return None
    except:
      return None
      
  def get_feed_cache(self):
    return [[f[FEEDID],f[FLAG],f[UNREAD],f[TOTAL],f[POLLFAIL],f[FIRSTENTRYTITLE]] for f in self._feedlist]
    
  def interrupt(self):
    self._cancel_load = [True,True]
    
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.