#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-
# 06/23/2004 - 01:01:40
# © 2004 Romain GUY <romain.guy@jext.org>
# Stump est un lecteur de documents RSS sous forme d'applet GNOME

##########################################################################################
# GLOBAUX
##########################################################################################

__version__ = "1.0"
__appname__ = "stump"
__author__  = "Romain GUY <romain.guy@jext.org>"
__date__    = "06/23/2004 - 01:35:16"

##########################################################################################
# IMPORTS
##########################################################################################
# imports Python
import os
import os.path
import sys
import urllib
import webbrowser

# imports RSS
from RSS import ns, TrackingChannel

# imports relatifs à GTK et GNOME
import pygtk
import gtkhtml2
import gtk
import gnome
import gnome.applet
import gobject

##########################################################################################
# APPLET STUMP
##########################################################################################

class StumpApplet(gnome.applet.Applet):
  """Classe principale de l'applet Stump RSS Reader."""

  def savePreferences(self, event, data = None):
    """Enregistre les préférences."""
    home = os.path.expanduser("~/.stump")
    if not os.path.exists(home):
      os.mkdir(home)
    config = open(home + "/config", "w")
    config.write(self.input.get_text() + "\n")
    self.rssURL = self.input.get_text()
    config.close()
    self.configFrame.destroy()

  def loadPreferences(self):
    """Charge les préférences."""
    home = os.path.expanduser("~/.stump/config")
    if not os.path.exists(home):
      self.rssURL = "http://www.progx.org/backend/progx.rss"
      return
    config = open(home, "r")
    self.rssURL = config.readline()
    config.close()

  def showProperties(self, event, data = None):
    """Affiche la fenêtre des propriétés de l'applet."""
    label = gtk.Label("RSS URL: ")
    self.input = gtk.Entry()
    self.input.set_text(self.rssURL)

    hbox = gtk.HBox()
    hbox.add(label)
    hbox.add(self.input)

    button = gtk.Button("Save")
    button.connect("clicked", self.savePreferences)

    vbox = gtk.VBox()
    vbox.add(hbox)
    vbox.add(button)

    self.configFrame = gtk.Window(gtk.WINDOW_TOPLEVEL)
    self.configFrame.add(vbox)
    self.configFrame.set_title("Stump Preferences")
    self.configFrame.set_destroy_with_parent(gtk.TRUE)
    self.configFrame.set_resizable(gtk.FALSE)
    self.configFrame.set_position(gtk.WIN_POS_CENTER)
    self.configFrame.show_all()

  def showRSSContent(self):
    """Affiche une fenêtre avec le contenu du flux RSS sélectionné."""
    tc = TrackingChannel()
    tc.encoding = "iso-8859-1"
    tc.parse(self.rssURL)
    
    RSS10_CHANNEL = (ns.rss10, 'channel')
    RSS10_LINK = (ns.rss10, 'link')
    RSS10_TITLE = (ns.rss10, 'title')
    RSS10_DESC = (ns.rss10, 'description')
    RSS10_ENCODED = (ns.content, 'encoded')

    channel = tc.get(RSS10_CHANNEL)
    items = tc.listItems()
    
    htmlBuffer = "<html><head></head><body><h1>" + channel.get(RSS10_TITLE, "Unknown") + "</h1>"
    htmlBuffer += '<a href="' + channel.get(RSS10_LINK, "http://www.python.org") + '">' +  channel.get(RSS10_LINK, "http://www.python.org") + "</a><br>"
    htmlBuffer += "<small>" + channel.get(RSS10_DESC, "No description.") + "</small><br><br>"

    for item in items:
      url = item[0]
      itemData = tc.getItem(item)
      htmlBuffer += "<h2>" + itemData.get(RSS10_TITLE, "No title.")
      htmlBuffer += ' <a href="' + itemData.get(RSS10_LINK, "http://www.python.org") + '">link</a></h2>'
      data = itemData.get(RSS10_ENCODED, None)
      if data is None:
        data.get(RSS10_DESC, "No information.")
      htmlBuffer += data + "<br><br>"

    htmlBuffer += "</body></html>"

    document = gtkhtml2.Document()
    document.clear()
    document.open_stream('text/html')
    document.write_stream(htmlBuffer.encode('iso-8859-1'))
    document.close_stream()
    document.connect('request_url', self.requestUrl)
    document.connect('link_clicked', self.linkClicked)

    view = gtkhtml2.View()
    view.set_document(document)
    view.show()

    scrollPane = gtk.ScrolledWindow()
    scrollPane.add(view)
    scrollPane.set_shadow_type(gtk.SHADOW_ETCHED_OUT)

    frame = gtk.Window(gtk.WINDOW_TOPLEVEL)
    frame.set_title(channel.get(RSS10_TITLE, "Unknown"))
    frame.set_destroy_with_parent(gtk.TRUE)
    #frame.set_decorated(gtk.FALSE)
    frame.add(scrollPane)
    frame.set_default_size(320, 240)
    frame.set_resizable(gtk.TRUE)
    frame.set_position(gtk.WIN_POS_CENTER)
    frame.show_all()

  def requestUrl(self, document, link, stream):
    """Gère la demande de lecture d'une URL."""
    _stream = urllib.urlopen(link)
    if _stream is None:
      return
    stream.write(_stream.read())

  def linkClicked(self, document, link):
    """Gère le suivi d'un lien."""
    webbrowser.open_new(link)

  def mouseButtonPress(self, widget, event):
    """Gestion de l'événement souris. Création du menu contextuel et affichage du flux RSS."""
    if event.type == gtk.gdk.BUTTON_PRESS:
      # clic 'gauche', on affiche le flux RSS paramétré dans l'application
      if event.button == 1:
        self.showRSSContent()
      # clic 'droit', on affiche le menu contextuel
      if event.button == 3:
        self.applet.setup_menu(self.popupMenu, self.popupVerbs, None)

  def mouseEnter(self, widget, event):
    """Lorsque la souris entre dans la eventbox nous illuminons le bouton."""
    self.button.set_from_stock('stump-logo-highlight', gtk.ICON_SIZE_BUTTON)

  def mouseLeave(self, widget, event):
    """Lorsque la souris quitte la eventbox nous `éteignons` le bouton."""
    self.button.set_from_stock('stump-logo', gtk.ICON_SIZE_BUTTON)

  def quit(self, event):
    """Détruit les ressources."""
    del self.applet

  def __init__(self, applet, iid):
    self.__gobject_init__()
    self.registerStockIcons()

    # membres
    self.applet = applet
    self.iid    = iid

    # définition du menu contextuel du clic droit de la souris
    self.popupMenu = """<popup name="button3">
      <menuitem name="Item 1" verb="Props" label="_Preferences..." pixtype="stock" pixname="gtk-properties" />
    </popup>"""
    # définition des actions du menu contextuel
    self.popupVerbs = [("Props", self.showProperties)]

    # initialise les options
    self.loadPreferences()

    # initialisation GNOME
    gnome.program_init(__appname__, __version__)

    # gestion des événements
    self.eventsBox = gtk.EventBox()
    self.eventsBox.connect("button_press_event", self.mouseButtonPress)
    self.eventsBox.connect("enter_notify_event", self.mouseEnter)
    self.eventsBox.connect("leave_notify_event", self.mouseLeave)

    self.button = gtk.Image()
    self.button.set_from_stock('stump-logo', gtk.ICON_SIZE_BUTTON)

    self.eventsBox.add(self.button)
    self.applet.add(self.eventsBox)

    # connexion du handler de destruction de l'applet puis affichage
    self.applet.connect("destroy", self.quit)
    self.applet.show_all()

  def registerStockIcons(self):
    """Initialise les icones du stock par défaut ainsi que les nôtres."""
    items = [('stump-logo', None, 0, 0, None),
             ('stump-logo-highlight', None, 0, 0, None)]
    gtk.stock_add(items)

    factory = gtk.IconFactory()
    factory.add_default()

    for item in items:
      pixbuf = gtk.gdk.pixbuf_new_from_file(runtimePath + item[0] + '.png')
      if pixbuf:
        iconSet = gtk.IconSet(pixbuf)
        factory.add(item[0], iconSet)

##########################################################################################
# FABRIQUE
##########################################################################################

gobject.type_register(StumpApplet)

def stumpAppletFactory(applet, iid):
  StumpApplet(applet, iid)
  return gtk.TRUE

##########################################################################################
# POINT D'ENTREE
##########################################################################################

# on sauvegarde le chemin d'exécution du programme
runtimePath = os.path.dirname(sys.argv[0]) + '/'

# démarrage en mode stand-alone pour les tests
if len(sys.argv) > 1 and sys.argv[1] == "run-in-window":
  frame = gtk.Window(gtk.WINDOW_TOPLEVEL)
  frame.set_title("Stump RSS Reader")
  frame.connect("destroy", gtk.mainquit) 
  app = gnome.applet.Applet()
  stumpAppletFactory(app, None)
  app.reparent(frame)
  frame.show_all()
  gtk.main()

# démarrage pour enregistrement dans bonobo
if __name__ == '__main__':
  # enregistre l'applet auprès du bonobo-activation-server
  gnome.applet.bonobo_factory("OAFIID:GNOME_StumpApplet_Factory",  StumpApplet.__gtype__,
                               "stump", "1.0", stumpAppletFactory) 