#!/usr/bin/env python2.5
#
# This file is part of isearch-edit, a tool to create and edit 
# files for the maemo internet search applet
#
# (c) 2007 Thomas Schmidt <tschmidt@debian.org>
#
# This code 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 3
# of the License, or (at your option) any later version.
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY 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 isearch-edit. If not, see <http://www.gnu.org/licenses/>.
#

import gtk
import hildon 
import os
import gobject
import osso
import sys

from isearchedit import constants
from isearchedit import misparser

class IsearchEditApp(hildon.Program):
  def __init__(self):
    hildon.Program.__init__(self)

    self.window = hildon.Window()
    self.window.connect("destroy", self.quit)
    self.add_window(self.window)

    self.window.connect("key-press-event", self.on_key_press)
    self.window.connect("window-state-event", self.on_window_state_change)
    self.window_in_fullscreen = False # The window isn't in full screen mode initially.

    self.osso_c   = osso.Context("MisEdit", constants.ISEARCHEDIT_VERSION, True)
    self.note     = osso.SystemNote(self.osso_c)
    self.osso_rpc = osso.Rpc(self.osso_c)
    self.osso_rpc.set_rpc_callback("org.maemo.isearchedit", "/org/maemo/isearchedit", "org.maemo.isearchedit", self.dbus_callback, self.osso_c)

    # vbox holding the window content
    self.vbox = gtk.VBox()
    
    # filelist
    self.misview, self.misscrolled = self.build_model()
    self.vbox.pack_start(self.misscrolled, expand=True, fill=True)
    
    # add vbox to main window
    self.window.add(self.vbox)
    
    # create toolbar
    self.toolbar = self.build_toolbar()
    self.window.add_toolbar(self.toolbar)
    
    # setup menu
    self.menu = self.build_menu()
    self.window.set_menu(self.menu)
    
    self.window.show_all()

  def build_toolbar(self):
    toolbar = gtk.Toolbar()
    toolbar.set_style(gtk.TOOLBAR_ICONS)

    toolbar_item = gtk.ToolButton("Quit")
    toolbar_item.set_stock_id(gtk.STOCK_QUIT)
    toolbar_item.connect("clicked", self.quit)
    toolbar.insert(toolbar_item, -1)

    toolbar_item = gtk.ToolButton("New")
    toolbar_item.set_stock_id(gtk.STOCK_NEW)
    toolbar_item.connect("clicked", self.on_new_clicked)
    toolbar.insert(toolbar_item, 0)

    toolbar_item = gtk.ToolButton("Select icon")
    toolbar_item.set_stock_id(gtk.STOCK_EDIT)
    toolbar_item.connect("clicked", self.on_icon_select)
    toolbar.insert(toolbar_item, 1)

    toolbar_item = gtk.ToolButton("Save Search")
    toolbar_item.set_stock_id(gtk.STOCK_SAVE)
    toolbar_item.connect("clicked", self.on_icon_select)
    toolbar.insert(toolbar_item, 2)

    toolbar_item = gtk.ToolButton("Delete")
    toolbar_item.set_stock_id(gtk.STOCK_DELETE)
    toolbar_item.connect("clicked", self.on_delete_clicked)
    toolbar.insert(toolbar_item, 3)

    toolbar_item = gtk.SeparatorToolItem()
    toolbar_item.set_draw(False)
    toolbar_item.set_expand(True)
    toolbar.insert(toolbar_item, 4)
    
    toolbar.show_all()

    return toolbar

  def make_view(self, model):
    # Create the view itself.
    view = gtk.TreeView(model)
   
    renderer = gtk.CellRendererPixbuf()
    column = gtk.TreeViewColumn("Icon", renderer, pixbuf=3)
    view.append_column(column)

    renderer = gtk.CellRendererText()
    renderer.set_property('editable', True)
    renderer.connect('edited', self.on_edited_cell, (model, 1))
    column = gtk.TreeViewColumn("Name", renderer, text=1)
    view.append_column(column)

    renderer = gtk.CellRendererText()
    renderer.set_property('editable', True)
    renderer.connect('edited', self.on_edited_cell, (model, 2))
    column = gtk.TreeViewColumn("URL (%s will be replaced with the search-string)", renderer, text=2)
    view.append_column(column)

    # row-activated seems to work with chinook, but not with bora!!!???
    view.connect("row-activated", self.on_icon_select)
    view.set_headers_visible(True)
    
    # Create scrollbars around the view.
    scrolled = gtk.ScrolledWindow()
    scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    scrolled.add(view)

    return view, scrolled

  def build_model(self):
    path = constants.MIS_DIR
    
    model = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING, gtk.gdk.Pixbuf)
    
    dirList = os.listdir(path)
    for filename in dirList:
      mis   = misparser.MisParser(path + "/" + filename)
      url   = mis.MisToUrl()
      name  = mis.get_name()
     
      try:
        icon = gtk.gdk.pixbuf_new_from_file(mis.get_icon())
      except gobject.GError:
        icon = None
    
      iter = model.insert_before(None, None)
      model.set_value(iter, 0, mis)
      model.set_value(iter, 1, name)
      model.set_value(iter, 2, url)
      model.set_value(iter, 3, icon)

    view, scrolled = self.make_view(model)
    view.set_reorderable(False)

    return view, scrolled

  def build_menu(self):
    menu = gtk.Menu()
    help_menu = gtk.Menu()

    # Create menuitems
    new_item = gtk.MenuItem("New...")
    edit_item = gtk.MenuItem("Select icon...")
    delete_item = gtk.MenuItem("Delete...")
    quit_item = gtk.MenuItem("Quit")
    about_item = gtk.MenuItem("About")

    help_item = gtk.MenuItem("Help")
    help_item.set_submenu(help_menu)

    help_menu.append(about_item)

    # Add items to menu
    menu.append(new_item)
    menu.append(edit_item)
    menu.append(delete_item)
    menu.append(help_item)
    menu.append(gtk.SeparatorMenuItem())
    menu.append(quit_item)

    # Attach callback functions
    quit_item.connect("activate", gtk.main_quit)
    edit_item.connect("activate", self.on_icon_select)
    about_item.connect("activate", self.on_about_activate)
    new_item.connect("activate", self.on_new_clicked)
    delete_item.connect("activate", self.on_delete_clicked)

    # Now show menu items
    menu.show_all()

    return menu
 
  def on_edited_cell(self, cell, path, new_text, user_data):
    liststore, column = user_data

    mis       = liststore[path][0]
    icon      = mis.get_icon()
    
    if column == 1:
      name  = new_text
      url   = liststore[path][2]
    if column == 2:
      url   = new_text
      name  = liststore[path][1]
 
    try:
      mis.UrlToMis(url, name, icon)
    except IndexError:
      #dialog = hildon.Note ("information", (self.window, "URL not valid!\n(use %s as search-string)", gtk.STOCK_DIALOG_INFO) )
      #dialog.set_button_text("Ok")
      #dialog.run()
      #dialog.destroy()
      return

    # try to find a good filename, if it is None currently 
    # and if the Name cell was edited
    if mis.get_filename() == None and column == 1:
      filename  = constants.MIS_DIR + "/" + name.lower() + "-search.xml"
      
      retry = 1
      while os.path.exists(filename):
        filename = constants.MIS_DIR + "/" + name.lower() + str(retry) + "-search.xml"
        retry = retry + 1
        
      mis.set_filename(filename)

    # TODO: do not write mis, just set the color of the text to red
    mis.write_mis()
    liststore[path][column] = new_text
    
  def on_new_clicked(self, widget, *args):
    model, old_iter = self.misview.get_selection().get_selected()
  
    iconpath  = constants.ICON_DUMMY
    mis       = misparser.MisParser(None)
    name      = 'New Search'
    url       = 'http://example.org?search=%s'
  
    mis.set_name(name)
  
    try:
      icon = gtk.gdk.pixbuf_new_from_file(iconpath)
      mis.set_icon(iconpath)
    except gobject.GError:
      icon = None
      
    iter = model.insert_before(None, None)
    model.set_value(iter, 0, mis)
    model.set_value(iter, 1, name)
    model.set_value(iter, 2, url)
    model.set_value(iter, 3, icon)
    
  def on_icon_select(self, widget, *args):
    model, old_iter = self.misview.get_selection().get_selected()
    
    mis   = model.get_value(old_iter, 0)
   
    dlg = hildon.FileChooserDialog(self.window, gtk.FILE_CHOOSER_ACTION_OPEN)
    dlg.set_title("Select Icon")
    response = dlg.run()
    dlg.hide()

    if response == gtk.RESPONSE_OK:
      filename = dlg.get_filename()
      try:
        icon = gtk.gdk.pixbuf_new_from_file(filename)
        
        # check if image size is max. 95x30 pixel
        max_width   = 95
        max_height  = 30
        if icon.get_width() > max_width or icon.get_height() > max_height:
          note = "Maximum icon size is " + str(max_width)+ "x" + str(max_height) + "px,\nyour selection is " + str(icon.get_width()) + "x" + str(icon.get_height()) + "px big!"
          dialog = hildon.Note ("information", (self.window, note, gtk.STOCK_DIALOG_INFO) )
          dialog.set_button_text("Ok")
          dialog.run()
          dialog.destroy()
          return

        mis.set_icon(filename)
        model.set_value(old_iter, 3, icon)
        mis.write_mis()
      except gobject.GError:
        dialog = hildon.Note ("information", (self.window, "Selected file is not a valid image!", gtk.STOCK_DIALOG_INFO) )
        dialog.set_button_text("Ok")
        dialog.run()
        dialog.destroy()
    dlg.destroy()

  def on_delete_clicked(self, widget, *args):
    model, old_iter = self.misview.get_selection().get_selected()
    
    try:
      mis = model.get_value(old_iter,0)
    except TypeError:
      dialog = hildon.Note ("information", (self.window, "Please select the item you want to delete!", gtk.STOCK_DIALOG_INFO) )
      dialog.set_button_text("Ok")
      dialog.run()
      dialog.destroy()
      return

    note = "Do you really want to delete the " + mis.get_name() + " Search?"
    dlg = hildon.Note ("confirmation", (self.window, note, gtk.STOCK_DIALOG_WARNING) )
    dlg.set_button_texts ("Yes", "No")
    response = dlg.run()
    dlg.destroy()

    if response == gtk.RESPONSE_OK:
      filename = mis.get_filename()
      if filename != None:
        os.remove(filename)
      model.remove(old_iter)
  
  def on_about_activate(self, widget, *args):
    dlg = gtk.AboutDialog()

    dlg.set_name('isearch-edit')
    dlg.set_comments('Editor for Maemo internet search files')
    dlg.set_authors([
        'Thomas Schmidt',
        '<tschmidt@debian.org>',
    ])
    dlg.set_copyright('(c) 2007-2008, Thomas Schmidt')
    dlg.set_version(constants.ISEARCHEDIT_VERSION)

    dlg.run()
    dlg.destroy()

  def on_window_state_change(self, widget, event, *args):
    if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
      self.window_in_fullscreen = True
    else:
      self.window_in_fullscreen = False

  def on_key_press(self, widget, event, *args):
    if event.keyval == constants.HILDON_HARDKEY_FULLSCREEN:
      if self.window_in_fullscreen:
        self.window.unfullscreen ()
      else:
        self.window.fullscreen ()

  def dbus_callback(self, interface, method, arguments, user_data):
    print "received RPC: " + method
    #self.note.system_note_infoprint("MisEdit: Received an RPC to %s." % method)

  def quit(self, evt):
    gtk.main_quit()

  def run(self):
    gtk.main()

def main():
  app = IsearchEditApp()
  app.run()

if __name__ == "__main__":
  sys.exit(main())

# vim: set expandtab tabstop=2 shiftwidth=2 autoindent smartindent
