#!/usr/bin/python2.5
# rapier: a small bible reader for maemo.
# Copyright 2007 Pierre Amadio 
# pierre.amadio@libertysurf.fr
#
# 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 version 2.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import sys
sys.path.append("/usr/share/rapier")
import gtk
import hildon
import osso
import Sword
import threading
import Queue
import time
import gobject
import re
try:
	from gnome import gnomevfs
except:
	import gnomevfs

try:
	from gnome import gconf 
except:
	import gconf

import swordutils
import os
import sqlite3
import string
"""
Does not work as expected...should change this.

http://maemo.org/development/documentation/tutorials/Maemo_tutorial_bora.html#internet

if os.environ.has_key("LD_PRELOAD"):
    os.environ["LD_PRELOAD"]=os.environ["LD_PRELOAD"]+':/usr/lib/libosso-ic-preload.so'
else:
    os.environ["LD_PRELOAD"]='/usr/lib/libosso-ic-preload.so'
"""


class aJob:
    """
     In order not to freeze the GUI when some time consuming tasks are being
     perfomed, the GUI is in a separate thread, and the time consuming tasks
     are being handled in a separate thread. Communication between the two
     thread is done by two Queue.Queue in wich instances of aJob are
     being sent.
    """

    def __init__(self,id,type,args={}):
        """
          instance variables:
          id: a unique job id
          type: the kind of job it is ('rightrpm_list','existing_rpm_list tree'
          and so on)
          args: some data as input
          result: this will store the result (content of the file, whatever)
        """
        self.id=id
        self.type=type
        self.args=args
        self.result=""

class ModuleManage:
    """This is the module management GUI"""
    
    def __init__(gPart,args={}):
        print "Entering ModuleManage"

class GuiPart(hildon.Program):
    """
       This class handle the actual GUI code.
    """
    def __init__(self,qQuery,qAnswer):
        swordutils.debug('------------------------------------------------')
        swordutils.debug('Rapier starts')
        hildon.Program.__init__(self)
        self.gconf=gconf.client_get_default()
        self.reload_manager()
        self.mainWindow = hildon.Window()
        self.mainWindow.connect("destroy",self.application_quit)
        self.mainWindow.connect("key-press-event",self.on_key_press)
        self.mainWindow.connect("window-state-event",\
                                self.on_window_state_change)
        self.timeoutHandler=gobject.timeout_add(100,self.processAnswer)
        self.jobCounter=0
        self.watchCursor=gtk.gdk.Cursor(gtk.gdk.WATCH)
        """False or: a sentence describing the last job """
        self.ioWait=False
        self.fullScreen=False
        self.searchDisplay=False
        self.osso_context = osso.Context("org.maemo.rapier", "0.0.1", False)  
        self.osso_rpc=osso.Rpc(self.osso_context)
        self.booksInfo=self.getAllBooks()
        self.installedModules=self.get_installedModules()
        self.remoteModules=[]
        self.selected_module=''
        self.selected_book=''
        self.selected_chapter=0
        self.maxChapter=0
        self.maxVerse=0
        self.selected_verse=0
        #is the touch screen currently pressed ?
        self.buttonPressed=False
        #how many unit of motion to change the display ?
        self.motion_adjust=0
        self.waitForSearchFlag=False
        self.waitForRemoteModulesFlag=False
        self.waitForModuleManagementFlag=False
        self.showStrongNumbers=False
        """ coordinate of the mouse last time there was a click.  """
        self.y={'old':0,'new':0}
        """indice=verse number, value=verse text"""
        self.textArray=[]
        self.textMarks=[]
        """ QueueQueue storing the job to perform"""
        self.qQuery=qQuery
        """ QueueQueue storing a job that has been performed."""
        self.qAnswer=qAnswer
        self.add_window(self.mainWindow)


        if not self.gconf.get_string("/apps/osso/rapier/strong_db"):
            self.strong_db=False
        else:
            self.strong_db=self.gconf.get_string("/apps/osso/rapier/strong_db")

        if not self.gconf.get_bool("/apps/osso/rapier/modules/carriage_return"):
            self.append_carriage_return=False
        else:
            self.append_carriage_return=True
        
        self.prepareInterface()
        self.preparePrefWindow()
        self.prepareManageModuleWindow()
        self.prepareWaitingWindow()
        self.fillBooks()        


        self.mainWindow.show_all()
        self.searchProgressbar.hide()

        """
         If there is no data_path gconf variable, or if it looks dodgy
         then let set it
         to /home/user/sword
        """
        tmp_dataPath=self.gconf.get_string("/apps/osso/rapier/data_path")
        if not tmp_dataPath\
               or not self.is_valid_datapath(tmp_dataPath):
            defdst="/home/user/sword"
            src_uri=gnomevfs.URI("/usr/share/sword")
            dst_uri=gnomevfs.URI(defdst)
            try:
                test=gnomevfs.xfer_uri_list([src_uri],[dst_uri],\
                                       gnomevfs.XFER_RECURSIVE,\
                                       gnomevfs.XFER_ERROR_MODE_ABORT,\
                                       gnomevfs.XFER_OVERWRITE_ACTION_REPLACE_ALL)

                
                self.gconf.set_string("/apps/osso/rapier/data_path",defdst)
            except gnomevfs.Error,fault:
                snt="Problem setting data_path to /usr/share/sword: %s"%fault
                swordutils.debug(snt)
                self.show_message(snt)

        """
        First thing to do is to fill the menu with
        the list of available modules
        """
        self.refresh_module_list()
        if  self.gconf.get_string("/apps/osso/rapier/bookmarks/start"):
            self.go_to_bookmark(\
                                self.gconf.get_string("/apps/osso/rapier/bookmarks/start"))

    def application_quit(self,win):
        gtk.main_quit()
        position="%s %d:%d"%\
                  (self.selected_book,\
                   self.selected_chapter,\
                   self.selected_verse)
        swordutils.debug("Setting bookmarks to:'%s'"%position)
        self.gconf.set_string("/apps/osso/rapier/bookmarks/start",position)

    def reload_manager(self):
        self.mgr = swordutils.get_manager()

        
    def get_defaultModule(self):
        return self.gconf.get_string('/apps/osso/rapier/modules/default')

    def get_installedModules(self):
        out={}
        for m in self.mgr.getModules().values():
            out[m.Name()]=m.Description()
        return out
    
    def getAllBooks(self):
        """
         Return an array:
         [{'testament': 1, 'bookCount': 1, 'name': 'Genesis', 'abbr': 'Gen'},
         {'testament': 1, 'bookCount': 2, 'name': 'Exodus', 'abbr': 'Exod'},
        """
        vk=Sword.VerseKey()
        out=[]
        for i in range(1,3):
          vk.Testament(i)
          for j in range(1,vk.bookCount(i)+1):
             vk.Book(j)
             tmp={}
             tmp['name']=vk.bookName(i,j)
             tmp['abbr']=vk.getBookAbbrev()
             tmp['testament']=i
             tmp['bookCount']=j
             out.append(tmp)
        return out

    def getInfoBasedOnAbbr(self,abbr):
        """
        Return info related to a book based on its abbreviation (ie 'Gen')
        """
        #vk=Sword.VerseKey()
        for cur in self.booksInfo:
            if cur['abbr']==abbr:
                return cur
        sys.exit("no such book : %s"%abbr)    
        

    def get_info_from_refs(self,ref):
        reg=re.compile("^(\S+)\s+(\d+):(\d+)$")
        search=reg.search(ref)
        if search:
            out={}
            out['abbr']=search.group(1)
            out['chapter']=search.group(2)
            out['verse']=search.group(3)
        else:
            print "Cannot regexp '%s'"%ref
            swordutils.debug("Cannot regexp '%s'"%ref)
            out={}
            out['abbr']='Gen'
            out['chapter']='1'
            out['verse']='1'

        return out 

    def fillBooks(self):
        for cur in self.booksInfo:
            abr=cur['abbr']
            self.mainWindow.book_tb_combo.append_text(abr)
        self.mainWindow.book_tb_combo.set_active_iter(\
            self.mainWindow.book_tb_combo.get_model().get_iter((0,)))

    def fillChapters(self):
        """ fill the chapter combo box"""
        tmp={}
        vk=Sword.VerseKey()
        tmp=self.getInfoBasedOnAbbr(self.selected_book)
        nbr_chapters=vk.chapterCount(tmp['testament'],tmp['bookCount'])
        self.maxChapter=nbr_chapters
        self.mainWindow.chapter_tb_combo.get_model().clear()
        for i in range(nbr_chapters):
            nbr=i+1
            self.mainWindow.chapter_tb_combo.append_text(str(nbr))
        self.mainWindow.chapter_tb_combo.set_active_iter(\
            self.mainWindow.chapter_tb_combo.get_model().get_iter((0,)))
        

    def fillVerses(self):
        """ fill the verses combo box"""
        vk=Sword.VerseKey()
        tmp=self.getInfoBasedOnAbbr(self.selected_book)
        self.mainWindow.verse_tb_combo.get_model().clear()
        self.maxVerse=vk.verseCount(tmp['testament'],tmp['bookCount'],\
                                     self.selected_chapter)
        for i in range(self.maxVerse):
            nbr=1+i
            self.mainWindow.verse_tb_combo.append_text(str(nbr))
        self.mainWindow.verse_tb_combo.set_active_iter(\
            self.mainWindow.verse_tb_combo.get_model().get_iter((0,)))
            
        
    def get_combo_active_text(self,combobox):
        model=combobox.get_model()
        active=combobox.get_active()
        if active<0:
            return None
        out= model[active][0]
        return out


    def switchSearchWidget(self,widget):
        """ hide or show the search horizontal pannel"""
        if self.searchDisplay:
            self.textDisplay_hpaned.set_position(0)
            self.searchDisplay=False
        else:
            self.textDisplay_hpaned.set_position(200)
            self.searchDisplay=True

            
    def prepareInterface(self):
        self.mainWindow.MainMenu=gtk.Menu()
        self.mainWindow.ModuleChooserMenu=gtk.Menu()
        self.mainWindow.itemSubMenuModuleChooser=gtk.MenuItem("Modules")
        self.mainWindow.MainMenu.append(\
            self.mainWindow.itemSubMenuModuleChooser)

        #Manage menu item
        self.mainWindow.itemMenuManage=gtk.MenuItem("Manage")
        self.mainWindow.MainMenu.append(self.mainWindow.itemMenuManage)
        self.mainWindow.itemMenuManage.connect(\
            "activate",self.displayManageModuleWindow)

        self.mainWindow.itemMenuPref=gtk.MenuItem("Preferences")
        self.mainWindow.MainMenu.append(self.mainWindow.itemMenuPref)
        self.mainWindow.itemMenuPref.connect('activate',self.displayPrefWindow)
        
        self.mainWindow.set_menu(self.mainWindow.MainMenu)
                
        self.mainWindow.toolbar=gtk.Toolbar()
        self.mainWindow.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL);
        self.mainWindow.toolbar.set_style(gtk.TOOLBAR_BOTH_HORIZ);

        #Book ComboBox
        self.mainWindow.book_tb_item=gtk.ToolItem()
        self.mainWindow.book_tb_combo=gtk.combo_box_new_text()
        self.mainWindow.book_tb_item.add(self.mainWindow.book_tb_combo)
        self.mainWindow.book_tb_combo.connect('changed',\
                                              self.book_combo_changed)
        self.mainWindow.toolbar.insert(self.mainWindow.book_tb_item,0)

        #Chapter Combox
        self.mainWindow.chapter_tb_item=gtk.ToolItem()
        self.mainWindow.chapter_tb_combo=gtk.combo_box_new_text()
        self.mainWindow.chapter_tb_item.add(self.mainWindow.chapter_tb_combo)
        self.mainWindow.chapter_tb_combo.connect('changed',\
                                                 self.chapter_combo_changed)
        self.mainWindow.toolbar.insert(self.mainWindow.chapter_tb_item,1)

        #Verse Combo
        self.mainWindow.verse_tb_item=gtk.ToolItem()
        self.mainWindow.verse_tb_combo=gtk.combo_box_new_text()
        self.mainWindow.verse_tb_item.add(self.mainWindow.verse_tb_combo)
        self.mainWindow.verse_tb_combo.connect(\
            'changed',self.verse_combo_changed)
        self.mainWindow.toolbar.insert(self.mainWindow.verse_tb_item,2)

        #Strong Number checkbox.
        self.mainWindow.strong_number_item=gtk.ToolItem()
        self.mainWindow.strong_number_check_b=gtk.CheckButton(\
            label="Strong's Number",use_underline=False)
        self.mainWindow.strong_number_check_b.connect("clicked",\
            self.strong_number_check_b_clicked)
        self.mainWindow.strong_number_item.add(\
            self.mainWindow.strong_number_check_b)
        self.mainWindow.toolbar.insert(\
            self.mainWindow.strong_number_item,3)

        self.mainWindow.back_b_item=gtk.ToolItem()
        self.mainWindow.back_b=gtk.Button()
        self.mainWindow.back_b_item.add(self.mainWindow.back_b)
        self.mainWindow.back_b.connect('clicked',self.back_b_clicked)
        self.mainWindow.toolbar.insert(self.mainWindow.back_b_item,3)
        self.mainWindow.back_image=gtk.Image()
        self.mainWindow.back_image.set_from_file(\
            '/usr/share/themes/default/images/qgn_plat_arrow_left_normal.png')
        self.mainWindow.back_b.add(self.mainWindow.back_image)

        self.mainWindow.next_b_item=gtk.ToolItem()
        self.mainWindow.next_b=gtk.Button()
        self.mainWindow.next_b_item.add(self.mainWindow.next_b)
        self.mainWindow.next_b.connect('clicked',self.next_b_clicked)
        self.mainWindow.next_image=gtk.Image()
        self.mainWindow.next_image.set_from_file(\
            '/usr/share/themes/default/images/qgn_plat_arrow_right_normal.png')
        self.mainWindow.next_b.add(self.mainWindow.next_image)

        self.mainWindow.toolbar.insert(self.mainWindow.next_b_item,4)

        
        self.mainWindow.displaySearch_item=gtk.ToolItem()
        self.mainWindow.displaySearch_b=gtk.Button()
        self.mainWindow.displaySearch_item.add(self.mainWindow.displaySearch_b)
        self.mainWindow.displaySearch_b.connect('clicked',\
                                                self.switchSearchWidget)
        self.mainWindow.switchSearch_image=gtk.Image()
        self.mainWindow.switchSearch_image.set_from_file(\
            '/usr/share/icons/hicolor/26x26/hildon/qgn_addr_icon_search_service.png')
        self.mainWindow.displaySearch_b.add(self.mainWindow.switchSearch_image)
        self.mainWindow.toolbar.insert(self.mainWindow.displaySearch_item,5)
        

        self.mainWindow.toolbar.show()
        self.mainWindow.add_toolbar(self.mainWindow.toolbar)

        #Main Text Window
        self.textDisplay_Vbox=gtk.VBox(True, 1)
        self.textDisplay_hpaned=gtk.HPaned()
        self.textDisplay_scrolledWindow=gtk.ScrolledWindow()

        hildon.hildon_helper_set_thumb_scrollbar(\
            self.textDisplay_scrolledWindow, True)

        self.textDisplay_textview= gtk.TextView()
        self.textDisplay_textview.set_editable(False)
        self.textDisplay_textview.set_cursor_visible(True)
        self.textDisplay_textview.connect('button-press-event',\
                                          self.button_press)
        self.textDisplay_textview.connect('button-release-event',\
                                          self.button_release) 
        self.textDisplay_textview.connect('motion-notify-event',\
                                          self.motion_notify)
        gtk.settings_get_default().props.gtk_font_name = "Sans 24"
        
        self.textDisplay_textview.set_wrap_mode(gtk.WRAP_WORD)
        self.fontSize=18
        self.textDisplay_buffer = self.textDisplay_textview.get_buffer()
        self.textDisplay_buffer.connect('mark_set', self.mark_set) 

        self.indiceTag=self.textDisplay_buffer.create_tag('indiceTag')
        self.indiceTag.set_property('size-points',self.fontSize)
        self.indiceTag.set_property('scale',.5)
        self.highlightTag=self.textDisplay_buffer.create_tag('highlightTag')
        self.highlightTag.set_property('size-points',self.fontSize)
                
        self.highlightTag.set_property('background','grey')
        self.normalTag=self.textDisplay_buffer.create_tag('normalTag')
        self.normalTag.set_property('size-points',self.fontSize)

        self.normalTag.set_property('background','white')
        self.textDisplay_scrolledWindow.set_policy(\
            gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        
        

        self.mainWindow.add(self.textDisplay_Vbox)
        self.textDisplay_Vbox.pack_start(self.textDisplay_hpaned)

        
        #Search slide.
        self.searchVbox=gtk.VBox(False,0)
        #self.searchInputBox=gtk.HBox(False,0)
        self.searchEntry=gtk.Entry()
        self.searchGo=gtk.Button("Search")
        self.searchGo.connect("clicked",self.search_b_clicked)
        self.searchProgressbar=gtk.ProgressBar()

        self.searchResult_scrolled_window=gtk.ScrolledWindow()

        hildon.hildon_helper_set_thumb_scrollbar(\
            self.searchResult_scrolled_window, True)

        
        self.searchResult_TreeView=gtk.TreeView()
        self.searchResult_TreeView.set_fixed_height_mode(True)
        
        self.searchResult_scrolled_window.add(self.searchResult_TreeView)
        self.searchResult_TreeView_selection=self.searchResult_TreeView.get_selection()
        self.searchResult_TreeView_selection.connect(\
            'changed',self.result_selection_changed)
        self.result_ts=gtk.TreeStore(str,str)

        
        self.searchVbox.pack_start(self.searchEntry,False,False)
        self.searchVbox.pack_start(self.searchGo,False,False)
        self.searchVbox.pack_start(self.searchProgressbar,False,False)
        #self.searchVbox.pack_start(self.searchInputBox,False,False)
        #self.searchInputBox.pack_start(self.searchEntry)
        #self.searchInputBox.pack_start(self.searchGo)

        self.searchVbox.pack_start(gtk.HSeparator(),False,False)
        self.searchVbox.pack_start(self.searchResult_scrolled_window,True,True)

        self.textDisplay_hpaned.set_position(0)
        self.textDisplay_hpaned.add(self.searchVbox)
        self.textDisplay_hpaned.add(self.textDisplay_scrolledWindow)
        self.textDisplay_scrolledWindow.add(self.textDisplay_textview)

        #Dictionary Display Window.
        self.dictDisplay_w=hildon.Window()
        self.dictDisplay_w.set_title("Dictionary")
        self.dictDisplay_w.set_modal(True)
        self.dictDisplay_w.set_transient_for(self.mainWindow)
        self.dictDisplay_w.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
        self.dictDisplay_text_sw=gtk.ScrolledWindow()

        hildon.hildon_helper_set_thumb_scrollbar(\
            self.dictDisplay_text_sw, True)

        self.dictDisplay_textview=gtk.TextView()
        self.dictDisplay_textview.set_editable(False)
        self.dictDisplay_textview.set_cursor_visible(False)
        self.dictDisplay_textview.set_wrap_mode(gtk.WRAP_NONE)
        self.dictDisplay_buffer = self.dictDisplay_textview.get_buffer()
        self.dictDisplay_text_sw.set_policy(\
            gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        
        self.dictDisplay_text_sw.add(self.dictDisplay_textview)
        
        self.dictDisplay_okb=gtk.Button('Ok')
        self.dictDisplay_okb.connect("clicked",self.hide_dic_window)
        self.dictDisplay_vb=gtk.VBox()
        self.dictDisplay_w.add(self.dictDisplay_vb)
        self.dictDisplay_vb.pack_start(self.dictDisplay_text_sw,True)
        self.dictDisplay_vb.pack_start(self.dictDisplay_okb,False)
        self.dictDisplay_w.resize(700,300)
        #self.dictDisplay_w.show_all()
        
        return True


    def refillPrefModuleList(self):
        defaultModule=self.get_defaultModule()
        selectedFlag=False
        iter=False
        self.prefModuleTabModel.clear()
        for m in self.installedModules.keys():
            curiter=self.prefModuleTabModel.append([m])
            if m==defaultModule:
                selectedFlag=curiter

        if selectedFlag:
            self.prefModuleTabCombo.set_active_iter(selectedFlag)
        else:
            self.prefModuleTabCombo.set_active(0)

            

    def getDeviceInfoFromFilename(self,filename):
        """
        filename is a string representing a ....filename (/media/mmc2/plop)

        It returns a dictionnary with the followinf key/values pair:
        device: tablet,mmc1 or mmc2
        icon: a picture path that match the device type
        basename: the file name (without prefix)

        If the filename is not /media/mmc1,/media/mmc2,or /home/user/MyDocs
        then it just returns some null data as this is not a valid location to
        store stuff anyway.
        """

        out={}
        mmreg=re.compile("^/media/(mmc[12])/(.*)$")
        tabletreg=re.compile("^/home/user/MyDocs/(.*)$")
        mmsearch=mmreg.search(filename)
        if mmsearch:
            out['device']=mmsearch.group(1)
            out['icon']='/usr/share/icons/hicolor/26x26/hildon/qgn_list_gene_removable_memory_card.png'
            out['basename']=mmsearch.group(2)
            return out

        tabletsearch=tabletreg.search(filename)
        if tabletsearch:
            out['device']='tablet'
            out['icon']='/usr/share/icons/hicolor/26x26/hildon/qgn_list_shell_mydevice.png'
            out['basename']=tabletsearch.group(1)
            return out

        out['device']=''
        out['icon']='/usr/share/icons/hicolor/26x26/hildon/qgn_list_filemanager.png'
        out['basename']=''

        return out


    def setCorrectFileChooserIcon(self, devInfo):

        self.prefModuleTabDirCurLocation.set_from_file(devInfo['icon'])

        self.prefModuleTabDirDevLabel.set_text(devInfo['device'])

        self.prefModuleTabDirFileLabel.set_text(devInfo['basename'])
        
    def preparePrefWindow(self):
        self.prefWindow = gtk.Dialog()
        self.prefWindow.set_title("Preferences")
        #self.prefWindow.set_decorated(False)
        self.prefWindow.set_modal(True)
        self.prefWindow.set_transient_for(self.mainWindow)

        """
        preference window countain a vbox, a notebook and 2 button in a Hbox
           -------------------
          |                   |
          |   ------------    |
          |  |            |   |                  
          |  |  Notebook  |   |
          |  |            |   |        
          |   ------------    |
          |-------------------|
          |   -----------     |
          |  | Ok |Cancel|    |
          |   -----------     |
           ------------------- 

        """
        self.prefVbox = self.prefWindow.vbox
        """
        http://www.pygtk.org/docs/pygtk/class-gtknotebook.html
        """
        self.prefNotebook=gtk.Notebook()
        self.prefVbox.pack_start(self.prefNotebook,False,False)

        #Module Page
        self.prefModuleTab=gtk.VBox(False,0)
        #Module: Default.
        self.prefModuleTabDefault=gtk.HBox(True,0)
        self.prefModuleTabLabel=gtk.Label()
        self.prefModuleTabLabel.set_text('Default Module')
        self.prefModuleTabDefault.pack_start(\
            self.prefModuleTabLabel,True,False)
        self.prefModuleTabModel=gtk.ListStore(gobject.TYPE_STRING)
        self.prefModuleTabCombo=gtk.ComboBox(self.prefModuleTabModel)
        self.prefModuleTabCell=gtk.CellRendererText()
        self.prefModuleTabCombo.pack_start(self.prefModuleTabCell, True)
        self.prefModuleTabCombo.add_attribute(self.prefModuleTabCell,'text', 0)
        self.prefModuleTabDefault.pack_start(\
            self.prefModuleTabCombo,True,False)
        #Module: Directory
        self.prefModuleTabDir=gtk.HBox(True,0)
        self.prefModuleTabLabel=gtk.Label()
        self.prefModuleTabLabel.set_text('Storage Directory')
        self.prefModuleTabDir.pack_start(self.prefModuleTabLabel,True,False)
        self.prefModuleTabDirValue=gtk.HBox(False,5)
        self.prefModuleTabDir.pack_start(self.prefModuleTabDirValue)
        if self.mgr.prefixPath:
            devInfo=self.getDeviceInfoFromFilename(self.mgr.prefixPath)
        else:
            devInfo=self.getDeviceInfoFromFilename('')
        self.prefSelectedSwordDataPath=self.mgr.prefixPath
        self.prefModuleTabDirCurLocation=gtk.Image()
        self.prefModuleTabDirDevLabel=gtk.Label()
        self.prefModuleTabDirFileLabel=gtk.Label()
        self.prefModuleTabDirValue.pack_start(self.prefModuleTabDirCurLocation\
                                              ,True,False)
        self.prefModuleTabDirValue.pack_start(self.prefModuleTabDirDevLabel\
                                              ,True,False)
        self.prefModuleTabDirValue.pack_start(self.prefModuleTabDirFileLabel,\
                                              True,False)
        self.setCorrectFileChooserIcon(devInfo)
        self.prefModuleTabDirChange_b=gtk.Button('Change')
        self.prefModuleTabDirChange_b.connect(\
            'clicked',self.prefModuleTabDirChange_bClicked)
        self.prefModuleTabDirValue.pack_start(self.prefModuleTabDirChange_b,\
                                           True,False)

        #Modules: Append carriage return
        self.prefModuleTabCR=gtk.HBox(True,0)
        self.prefModuleTabCRLabel=gtk.Label()
        self.prefModuleTabCRLabel.set_label("Append new line\nat end of verse")
        self.prefModuleTabCR.pack_start(self.prefModuleTabCRLabel,True)
        self.prefModuleTabCR_box=gtk.CheckButton('')
        self.prefModuleTabCR.pack_start(self.prefModuleTabCR_box,True)
        


        self.prefModuleTab.pack_start(self.prefModuleTabDefault,False,False)
        self.prefModuleTab.pack_start(self.prefModuleTabCR,False,False)
        self.prefModuleTab.pack_start(self.prefModuleTabDir,False,False)
        
        self.refillPrefModuleList()
        self.prefNotebook.append_page(self.prefModuleTab,None)
        self.prefNotebook.set_tab_label_text(self.prefModuleTab,"Modules")

        #Debug page
        self.prefDebugTab=gtk.VBox(False,0)
        self.prefDebugHbox1=gtk.HBox(False,0)
        self.prefDebugLabel1=gtk.Label()
        self.prefDebugLabel1.set_text("Enable debug: ")
        self.prefDebugCheckBox=gtk.CheckButton('')
        self.prefDebugHbox1.pack_start(self.prefDebugLabel1,True)
        self.prefDebugHbox1.pack_start(self.prefDebugCheckBox,True)
        self.prefDebugTab.pack_start(self.prefDebugHbox1,True)
        self.prefDebugLabel2=gtk.Label()
        self.prefDebugLabel2.set_text(\
            "Location: %s"%swordutils.debugFile)
        self.prefDebugTab.pack_start(self.prefDebugLabel2,True)
        self.prefNotebook.append_page(self.prefDebugTab,None)
        self.prefNotebook.set_tab_label_text(self.prefDebugTab,"Debug")

        #Strong Number Database.
        self.prefStrongTabDir=gtk.VBox(True,1)
        self.prefStrongTabLabel=gtk.Label()
        self.prefStrongTabLabel.set_text("Strong number database location:")
        self.prefStrongTabDir.pack_start(self.prefStrongTabLabel,True,False)
        self.prefStrongTabDirValue=gtk.HBox(False,5)
        self.prefStrongTabDir.pack_start(self.prefStrongTabDirValue)
        if self.strong_db:
            devInfo=self.getDeviceInfoFromFilename(self.strong_db)
        else:
            devInfo=self.getDeviceInfoFromFilename("")
        self.prefStrongTabCurLocation=gtk.Image()
        self.prefStrongTabDevLabel=gtk.Label()
        self.prefStrongTabFileLabel=gtk.Label()
        self.prefStrongTabDirValue.pack_start(\
            self.prefStrongTabCurLocation,True,False)
        self.prefStrongTabDirValue.pack_start(\
            self.prefStrongTabDevLabel,True,False)
        self.prefStrongTabDirValue.pack_start(\
            self.prefStrongTabFileLabel)
        self.prefStrongTabCurLocation.set_from_file(devInfo['icon'])
        self.prefStrongTabDevLabel.set_text(devInfo["device"])
        self.prefStrongTabFileLabel.set_text(devInfo["basename"])
        self.prefStrongTabDirChange_b=gtk.Button("Change")
        self.prefStrongTabDirChange_b.connect(\
            'clicked',self.prefStrongTabDirChange_bClicked)
        self.prefStrongTabDirValue.pack_start(self.prefStrongTabDirChange_b,\
                                           True,False)
          
        self.prefNotebook.append_page(self.prefStrongTabDir,None)
        self.prefNotebook.set_tab_label_text(\
            self.prefStrongTabDir,"Strong Number")

        self.prefWindow.add_button("Apply", gtk.RESPONSE_OK)
        self.prefWindow.add_button("Cancel", gtk.RESPONSE_CANCEL)
        self.prefVbox.show_all()

    def prefModuleTabDirChange_bClicked(self,widget):
        prefModuleTabDirFileSelector=\
                                       hildon.FileChooserDialog(\
            self.prefWindow,gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,hildon.FileSystemModel(root_dir="/"))
        rep=prefModuleTabDirFileSelector.run()
        prefModuleTabDirFileSelector.hide()
        a=prefModuleTabDirFileSelector.get_filename()
        if rep==gtk.RESPONSE_OK:
            devInfo=self.getDeviceInfoFromFilename(a)
            self.setCorrectFileChooserIcon(devInfo)
            self.prefSelectedSwordDataPath=a
            
        elif rep==gtk.RESPONSE_CANCEL:
            prefModuleTabDirFileSelector.destroy()



    def is_valid_sqldb(self,fileName):
        try:
            db=sqlite3.connect(fileName)
            c=db.cursor()
            c.execute("Select count(*) from Words")
            db.close()
        except:
            return False
        return True
            
    def is_valid_datapath(self,path):
        if not  os.path.isdir(path):
            return False
        if not os.path.isdir(path+"/mods.d"):
            return False
        if not os.path.isdir(path+"/locales.d"):
            return False
        if not os.path.isdir(path+"/modules"):
            return False
        
        return True



    def prefStrongTabDirChange_bClicked(self,widget):
        prefStrongTabDirFileSelector=\
                                       hildon.FileChooserDialog(\
            self.prefWindow,gtk.FILE_CHOOSER_ACTION_OPEN,hildon.FileSystemModel(root_dir="/"))
        rep=prefStrongTabDirFileSelector.run()
        prefStrongTabDirFileSelector.hide()
        a=prefStrongTabDirFileSelector.get_filename()

        if not self.is_valid_sqldb(a):
            print "not a valid db"
            self.show_message("This does not seems like a sqlite database.")
            prefStrongTabDirFileSelector.destroy()
            return
        
        if rep==gtk.RESPONSE_OK:
            devInfo=self.getDeviceInfoFromFilename(a)
            self.prefStrongTabCurLocation.set_from_file(devInfo['icon'])
            self.prefStrongTabDevLabel.set_text(devInfo["device"])
            self.prefStrongTabFileLabel.set_text(devInfo["basename"])
            self.prefSelected_strong_db=a
            
        elif rep==gtk.RESPONSE_CANCEL:
            prefStrongTabDirFileSelector.destroy()


    def changePrefs(self):

        #Module preferences.
        iter=self.prefModuleTabCombo.get_active_iter()
        if iter:
            selectedModule=self.prefModuleTabModel.get_value(iter,0)
            self.gconf.set_string('/apps/osso/rapier/modules/default',\
                                  selectedModule)

        if self.prefSelectedSwordDataPath!=self.mgr.prefixPath:
            swordutils.debug(\
                "Changing data path to %s"%self.prefSelectedSwordDataPath)
            src_uri=gnomevfs.URI(self.mgr.prefixPath)
            dst_uri=gnomevfs.URI(self.prefSelectedSwordDataPath)

            try:
                gnomevfs.xfer_uri_list([src_uri],[dst_uri],\
                                       gnomevfs.XFER_RECURSIVE+\
                                       gnomevfs.XFER_REMOVESOURCE,\
                                       gnomevfs.XFER_ERROR_MODE_ABORT,\
                                       gnomevfs.XFER_OVERWRITE_ACTION_REPLACE_ALL)
                self.gconf.set_string('/apps/osso/rapier/data_path',
                                     self.prefSelectedSwordDataPath)
            except gnomevfs.Error,fault:
                snt="Problem changing data_path from %s to %s:\n%s"%\
                     (self.mgr.prefixPath,self.prefSelectedSwordDataPath,fault)
                self.show_message(snt)
                swordutils.debug(snt)
            
            self.reload_manager()

        #Debug
        self.gconf.set_bool('/apps/osso/rapier/debug/enabled',\
                              self.prefDebugCheckBox.get_active())

        #Strong Number database
        if self.prefSelected_strong_db!=self.strong_db:
            self.strong_db=self.prefSelected_strong_db
            self.gconf.set_string('/apps/osso/rapier/strong_db',\
                                self.strong_db)
        #Carriage_return
        self.gconf.set_bool('/apps/osso/rapier/modules/carriage_return',\
                            self.prefModuleTabCR_box.get_active())
        self.append_carriage_return=self.prefModuleTabCR_box.get_active()
        

    def cancelPrefs(self):
        #Let s put all default selection back.
        self.refillPrefModuleList()
        if self.mgr.prefixPath:
            devInfo=self.getDeviceInfoFromFilename(self.mgr.prefixPath)
        else:
            devInfo=self.getDeviceInfoFromFilename('')
        self.setCorrectFileChooserIcon(devInfo)

        self.prefDebugCheckBox.set_active(\
            self.gconf.get_bool('/apps/osso/rapier/debug/enabled'))

        self.prefModuleTabCR_box.set_active(\
            self.gconf.get_bool('/apps/osso/rapier/modules/carriage_return'))
        
    def displayPrefWindow(self,menuitem):
        self.prefDebugCheckBox.set_active(\
            self.gconf.get_bool('/apps/osso/rapier/debug/enabled'))
        self.prefSelected_strong_db=self.strong_db

        self.prefModuleTabCR_box.set_active(self.append_carriage_return)
        
        resp = self.prefWindow.run()
        self.prefWindow.hide()
        if resp == gtk.RESPONSE_OK:
            self.changePrefs()
        else:
            self.cancelPrefs()

    def displayManageModuleWindow(self,widget):
        self.fill_mgModLocalModel()
        self.refresh_remote_modules_tv()

        resp = self.mgModWindow.run()
        if resp == gtk.RESPONSE_OK:
            self.mgModOk_b_clicked()
        self.mgModWindow.hide()

    def mgModRemoteInstallCell_toggled(self,cell,path):
        origValue=self.mgModRemoteModel[path][0]
        isDirectory=self.mgModRemoteModel[path][4]
        curIter=self.mgModRemoteModel.get_iter(path)
        
        if isDirectory:
            nbr_children=self.mgModRemoteModel.iter_n_children(curIter)
            for index in range(0,nbr_children):
                newPath="%s:%i"%(path,index)
                self.mgModRemoteModel[newPath][0]=not origValue
                """
                self.mgModRemoteTv.expand_row(path,False)
                """
        else:
            if origValue:
                iter_parent=self.mgModRemoteModel.iter_parent(curIter)
                path_parent=self.mgModRemoteModel.get_path(iter_parent)
                self.mgModRemoteModel[path_parent][0]=False

        self.mgModRemoteModel[path][0] = not self.mgModRemoteModel[path][0]



    def mgModLocalIndex_toggled(self,cell, path):
        origValue=self.mgModLocalModel[path][2]

        if origValue:
            dialog = hildon.Note ("confirmation",\
                                  self.mgModWindow,\
                                   "Are you sure you want to "+\
                                   " destroy this index ?",\
                                   gtk.STOCK_DIALOG_WARNING\
                                  )
            dialog.set_button_texts ("Yes", "No")
            response = dialog.run()
            dialog.destroy()

            if response != gtk.RESPONSE_OK:
                return


        self.mgModLocalModel[path][2] = not self.mgModLocalModel[path][2]


    def mgModLocalRemove_toggled(self,cell, path):
        origValue=self.mgModLocalModel[path][3]
        if not origValue:
            dialog = hildon.Note ("confirmation",\
                                  self.mgModWindow,\
                                   "Are you sure you want to"+ \
                                   " uninstall this module ?",\
                                   gtk.STOCK_DIALOG_WARNING\
                                  )
            dialog.set_button_texts ("Yes", "No")
            response = dialog.run()
            dialog.destroy()

            if response != gtk.RESPONSE_OK:
                return
                
        self.mgModLocalModel[path][3] = not self.mgModLocalModel[path][3]
        
    def fill_mgModLocalModel(self):
        self.mgModLocalTv.freeze_child_notify()
        self.mgModLocalModel.clear()
        try:
            for c in self.mgModLocalTv.get_columns():
                self.mgModLocalTv.remove_column(c)
        except:
            print "oups"


        self.mgModLocalNameCell=gtk.CellRendererText()
        self.mgModLocalNameCol=gtk.TreeViewColumn('Name')
        self.mgModLocalTv.append_column(self.mgModLocalNameCol)
        self.mgModLocalNameCol.pack_start(self.mgModLocalNameCell,True)
        self.mgModLocalNameCol.set_attributes(self.mgModLocalNameCell,text=0)

        self.mgModLocalLangCell=gtk.CellRendererText()
        self.mgModLocalLangCol=gtk.TreeViewColumn('Lang')
        self.mgModLocalTv.append_column(self.mgModLocalLangCol)
        self.mgModLocalLangCol.pack_start(self.mgModLocalLangCell,True)
        self.mgModLocalLangCol.set_attributes(self.mgModLocalLangCell,text=1)

        self.mgModLocalIndexCell=gtk.CellRendererToggle()
        self.mgModLocalIndexCell.set_property('activatable', True)
        self.mgModLocalIndexCell.connect(\
            'toggled',self.mgModLocalIndex_toggled) 
        self.mgModLocalIndexCol=gtk.TreeViewColumn('Index')
        self.mgModLocalTv.append_column(self.mgModLocalIndexCol)
        self.mgModLocalIndexCol.pack_start(self.mgModLocalIndexCell,True)
        self.mgModLocalIndexCol.set_attributes(\
            self.mgModLocalIndexCell,active=2)

        
        self.mgModLocalRemoveCell=gtk.CellRendererToggle()
        self.mgModLocalRemoveCell.set_property('activatable', True)
        self.mgModLocalRemoveCell.connect(\
            'toggled',self.mgModLocalRemove_toggled) 
        self.mgModLocalRemoveCol=gtk.TreeViewColumn('Uninstall')
        self.mgModLocalTv.append_column(self.mgModLocalRemoveCol)
        self.mgModLocalRemoveCol.pack_start(self.mgModLocalRemoveCell,True)
        self.mgModLocalRemoveCol.set_attributes(\
            self.mgModLocalRemoveCell,active=3)
        
        
        for m in self.mgr.getModules().values():
            cur_name=m.Name()
            cur_lang=m.Lang()
            cur_clucene=swordutils.has_clucene_index(self.mgr, cur_name)
            self.mgModLocalModel.append(None,\
                                        [cur_name,cur_lang,cur_clucene,False])

        self.mgModLocalTv.thaw_child_notify()

    def mgModRemoteRefresh_b_clicked(self,widget):
        args={}
        args['osso_context']=self.osso_context
        args['data_path'] = swordutils.get_data_path()
        
        newJob=aJob(self.jobCounter,"remote_modules_list",args)
        self.putJob(newJob)
        self.waitForRemoteModulesFlag=True
        self.waitingWindow.set_property('description',
                "Waiting for remote modules list")
        self.waitingWindow.show_all()


    def mgModOk_b_clicked(self):
        mod_to_remove=[]
        idx_to_remove=[]
        idx_to_build=[]
        mod_to_install=[]
        
        locals=[]
        iter=self.mgModLocalModel.get_iter_first()

        if iter:
            while True:
                locals.append(\
                    {'name':self.mgModLocalModel.get_value(iter,0),\
                     'index':self.mgModLocalModel.get_value(iter,2),\
                     'uninstall':self.mgModLocalModel.get_value(iter,3)\
                     })
                iter=self.mgModLocalModel.iter_next(iter)
                if not iter:
                    break

        for cur in locals:
            #print cur
            curName=cur['name']
            if cur['uninstall']:
                mod_to_remove.append(curName)
            else:
                if (cur['index'] and not
                        swordutils.has_clucene_index(self.mgr, curName)):
                    idx_to_build.append(curName)
                if (not cur['index'] and
                        swordutils.has_clucene_index(self.mgr, curName)):
                    idx_to_remove.append(curName)


        iter=self.mgModRemoteModel.get_iter_first()

        if iter:
            while True:
                cur_path=self.mgModRemoteModel.get_path(iter)
                nbr_children=self.mgModRemoteModel.iter_n_children(iter)
                for index in range(0,nbr_children):
                    child_iter=self.mgModRemoteModel.iter_nth_child(\
                        iter,index)
                    ch_name=self.mgModRemoteModel.get_value(child_iter,1)
                    ch_get=self.mgModRemoteModel.get_value(child_iter,0)
                    if ch_get:
                        mod_to_install.append(ch_name)

                iter=self.mgModRemoteModel.iter_next(iter)
                if not iter:
                    break

        args={}
        args['mod_remove']=mod_to_remove
        args['install']=mod_to_install
        args['idx_build']=idx_to_build
        args['idx_remove']=idx_to_remove
        args['remote']=self.remoteModules
        args['osso_context']=self.osso_context
        args['data_path'] = swordutils.get_data_path()
        newJob=aJob(self.jobCounter,'module_management',args)
        self.putJob(newJob)
        self.waitForModuleManagementFlag=True
        self.waitingWindow.set_property('description',
                "Waiting for operation to perform.\n"+
                "(Index building may take a very,"+
                " very long time.)")
                                      
        self.waitingWindow.show_all()

    def prepareManageModuleWindow(self):
        self.mgModWindow = gtk.Dialog()
        self.mgModWindow.set_title("Manage Modules")
        self.mgModWindow.set_modal(True)
        self.mgModWindow.set_transient_for(self.mainWindow)
        self.mgModWindow.set_default_size(750,300)
        self.mgModVBox = self.mgModWindow.vbox
        self.mgModNotebook=gtk.Notebook()
        self.mgModVBox.pack_start(self.mgModNotebook)

        #Local Modules
        self.mgModLocalTab=gtk.VBox(False,0)
        self.mgModNotebook.append_page(self.mgModLocalTab)
        self.mgModNotebook.set_tab_label_text(self.mgModLocalTab,'Installed')
        self.mgModNotebook.set_tab_label_packing(self.mgModLocalTab,True,\
                                                 True,gtk.PACK_START)
        self.mgModLocalScrollWin=gtk.ScrolledWindow()

        hildon.hildon_helper_set_thumb_scrollbar(\
            self.mgModLocalScrollWin, True)

        self.mgModLocalTv=gtk.TreeView()
        self.mgModLocalTv.set_headers_visible(True)
        #http://maemo.org/pipermail/maemo-developers/2007-March/009258.html
        #self.mgModLocalTv.set_property('allow-checkbox-mode',False)
        self.mgModLocalScrollWin.add(self.mgModLocalTv)
        """
        name,Lang,Clucene index, Uninstall
        """
        self.mgModLocalModel=gtk.TreeStore(str,str,bool,bool)
        self.mgModLocalTv.set_model(self.mgModLocalModel)
        #self.mgModLocalTv.set_fixed_height_mode(True)
        self.mgModLocalTab.pack_start(self.mgModLocalScrollWin,True,True)
        
        
        #Remote Modules
        self.mgModRemoteTab=gtk.VBox(False,0)
        self.mgModNotebook.append_page(self.mgModRemoteTab)
        self.mgModNotebook.set_tab_label_text(self.mgModRemoteTab,'Remote')
        self.mgModRemoteScrollWin=gtk.ScrolledWindow()

        hildon.hildon_helper_set_thumb_scrollbar(\
            self.mgModRemoteScrollWin, True)

        self.mgModRemoteTv=gtk.TreeView()
        #self.mgModRemoteTv.set_headers_visible(True)        
        #self.mgModRemoteTv.set_property('allow-checkbox-mode',False)
        self.mgModRemoteScrollWin.add(self.mgModRemoteTv)
        """
        install,name,lang,description,is_directory
        """
        self.mgModRemoteModel=gtk.TreeStore(bool,str,str,str,bool)
        self.mgModRemoteModel.set_sort_column_id(1,gtk.SORT_ASCENDING)
        self.mgModRemoteTv.set_model(self.mgModRemoteModel)
        self.mgModRemoteTab.pack_start(self.mgModRemoteScrollWin,True,True)
        self.mgModRemoteRefresh_b=gtk.Button("Refresh")
        self.mgModRemoteRefresh_b.connect("clicked",\
                                          self.mgModRemoteRefresh_b_clicked)
        self.mgModRemoteTab.pack_start(self.mgModRemoteRefresh_b,False,False)
        
        self.mgModWindow.add_button("OK", gtk.RESPONSE_OK)
        self.mgModWindow.add_button("Cancel", gtk.RESPONSE_CANCEL)
        self.mgModVBox.show_all()


    def mgModRemoteInstallCell_data_func(self,column,renderer,model,iter):
        """
        Checkbox is only displayed in leaf nodes.
        """
        is_directory=model.get_value(iter,4)
        if is_directory:
            renderer.set_property('visible',False)
        else:
            renderer.set_property('visible',True)

    def refresh_remote_modules_tv(self):
        self.mgModRemoteModel.clear()
        for c in self.mgModRemoteTv.get_columns():
            self.mgModRemoteTv.remove_column(c)


        self.mgModRemoteInstallCell=gtk.CellRendererToggle()
        self.mgModRemoteInstallCell.set_property('activatable',True)
        self.mgModRemoteInstallCell.connect(\
            'toggled',self.mgModRemoteInstallCell_toggled)
                                            
        self.mgModRemoteInstallCol=gtk.TreeViewColumn('Install')
        self.mgModRemoteTv.append_column(self.mgModRemoteInstallCol)
        self.mgModRemoteInstallCol.pack_start(self.mgModRemoteInstallCell,True)

        self.mgModRemoteInstallCol.set_cell_data_func(\
            self.mgModRemoteInstallCell,self.mgModRemoteInstallCell_data_func)
        
        self.mgModRemoteInstallCol.set_attributes(\
            self.mgModRemoteInstallCell,active=0)

        self.mgModRemoteNameCell=gtk.CellRendererText()
        self.mgModRemoteInstallCol.pack_start(self.mgModRemoteNameCell,True)
        self.mgModRemoteInstallCol.set_attributes(\
            self.mgModRemoteNameCell,text=1)

        self.mgModRemoteDescCell=gtk.CellRendererText()
        self.mgModRemoteDescCol=gtk.TreeViewColumn('Description')
        self.mgModRemoteTv.append_column(self.mgModRemoteDescCol)
        self.mgModRemoteDescCol.pack_start(self.mgModRemoteDescCell,True)
        self.mgModRemoteDescCol.set_attributes(\
            self.mgModRemoteDescCell,text=3)

        byLang={}
        for i in self.remoteModules:

            if i['Name'] in self.installedModules:
                continue
            
            if 'Lang'not in i.keys():
                continue
            if i['Lang'] not in byLang.keys():
                byLang[i['Lang']]=[]
            byLang[i['Lang']].append(i)


        self.mgModRemoteTv.freeze_child_notify()

        localeMgr=Sword.LocaleMgr()
        for lang in byLang.keys():
            curlocale=localeMgr.getLocale(lang)
            if curlocale:
                lang_label=curlocale.getDescription()
            else:
                lang_label=lang
            
            iter=self.mgModRemoteModel.append(None,\
                                              [False,lang_label,'','',True]\
                                              )
            for mod in byLang[lang]:
                self.mgModRemoteModel.append(iter,\
                                             [\
                    False,mod['Name'],mod['Lang'],mod['Description'],False\
                    ])

        self.mgModRemoteTv.thaw_child_notify()
        
        
    def refresh_remote_modules(self,modules):
        self.waitForRemoteModulesFlag=False
        self.waitingWindow.hide()
        self.remoteModules=modules
        self.refresh_remote_modules_tv()        


    def show_message(self,message):
        note = hildon.Note("information",
                self.mainWindow, message, gtk.STOCK_DIALOG_INFO)
        note.set_modal(True)
        def cleanup(*args):
            note.destroy()
        note.connect('response', cleanup)
        note.show()

    def show_dic_window(self,message):
        self.dictDisplay_buffer.set_text(message)
        self.dictDisplay_w.show_all()

    def hide_dic_window(self,widget):
        self.dictDisplay_w.hide()

    def process_module_management(self,result):
        self.waitForModuleManagementFlag=False

        if result:
            snt="There were problems..."
        else:
            snt="Operation successful !"

        self.waitingWindow.hide()
        self.mgModWindow.hide()
        self.show_message(snt)
        self.reload_manager()
        self.refresh_module_list()
        self.refillPrefModuleList()
        
        return True


    def process_panic(self,job):
        message='Fatal error:%s'%job.args['message']
        note = hildon.Note("information",
                           self.mainWindow, message, gtk.STOCK_DIALOG_INFO)
        note.set_modal(True)
        def cleanup(*args):
            sys.exit()
        note.connect('response', cleanup)
        note.show()

        

    def prepareWaitingWindow(self):
        """self.mgModWindow"""
        self.waitingWinProgressBar=gtk.ProgressBar()
	self.waitingWindow = hildon.Note("cancel", self.mainWindow, "Waiting...", progressbar=self.waitingWinProgressBar)
#        self.waitingWindow = hildon.Note("cancel_with_progress_bar",(self.mainWindow, "Waiting...", self.waitingWinProgressBar))
        
    def on_key_press(self,widget,event):
        if event.keyval ==gtk.keysyms.F6:
            """Full screen key"""
            if self.fullScreen:
                self.mainWindow.unfullscreen()
                self.fullScreen=False
            else:
                self.mainWindow.fullscreen()
                self.fullScreen=True


        if event.keyval==65361:
            #print "left"
            if self.selected_chapter>2:
                tmp=int(self.selected_chapter)-1
                self.mainWindow.chapter_tb_combo.set_active(tmp-1)
                self.refresh_textArray()



        #if event.keyval==65362:
        #    print "up"

            
        if event.keyval==65363:
        #    print "right"
            
            if self.selected_chapter<self.maxChapter:
                self.mainWindow.chapter_tb_combo.set_active(\
                    self.selected_chapter)



        #if event.keyval==65364:
        #    print "down"


        if event.keyval==65477:
            self.change_font_size(-1)

        if event.keyval==65476:
            self.change_font_size(1)

    def button_press(self,widget,event):
        self.buttonPressed=True
        self.y['old']=self.y['new']
        self.y['new']=event.y

        """
        x=event.x
        y=event.y
        w=self.textDisplay_textview.get_window(gtk.TEXT_WINDOW_TEXT)
        buf_coord=self.textDisplay_textview.window_to_buffer_coords(\
            gtk.TEXT_WINDOW_TEXT,x,y)
        iter=self.textDisplay_textview.get_iter_at_location(buf_coord[0],buf_coord[1])
        line=iter.get_line()
        startIter=self.textDisplay_buffer.get_iter_at_line(line)
        upToTap=self.textDisplay_buffer.get_text(startIter,iter)
        allLine=self.textArray[line-1]

        print self.detect_strong_word(upToTap,allLine)
        """

        

    def button_release(self,widget,event):
        self.buttonPressed=False

    def mark_set(self,buffer,ite,mark):
        bound=self.textDisplay_buffer.get_selection_bounds()

        if not self.showStrongNumbers:
            return

        if len(bound) and mark.get_name()=="selection_bound":
            word=self.textDisplay_buffer.get_text(bound[0],bound[1])
            testament=self.getInfoBasedOnAbbr(self.selected_book)['testament']
            if re.compile("\D").search(word):
                return

            if testament==1:
                searchString="H"+str(word)
            else:
                searchString="G"+str(word)
            self.searchEntry.set_text(searchString)
            self.searchGo.clicked()
            if not self.searchDisplay:
                self.textDisplay_hpaned.set_position(150)
                self.searchDisplay=True

            
        
    def motion_notify(self,widget,event):
        if not self.buttonPressed:
            return

        adj=self.textDisplay_scrolledWindow.get_vadjustment()
        adjval=adj.get_value()

        cur=event.y
        modif=self.y['new']-cur
        self.motion_adjust+=modif
            
        self.y['old']=self.y['new']
        self.y['new']=cur

    def change_font_size(self,modif):
        self.fontSize+=modif
        self.normalTag.set_property('size-points',self.fontSize)
        self.highlightTag.set_property('size-points',self.fontSize)
        #testSize=self.fontSize-int(self.fontSize/10)
        #print "fontSize=",self.fontSize
        #print "testSize=",testSize
        self.indiceTag.set_property('size-points',self.fontSize)
        
    def on_window_state_change(self,widget,events):
        self.scrollToSelected()
        
    def putJob(self,newJob):
        """
        Push aJob ob in qQuery. 
        
        """
        self.jobCounter+=1
        #self.ioWait="Query #"+str(newJob.id)
        #self.statusbar.push(self.statusbar.get_context_id('cont'),self.ioWait)
        #self.mainWindow.set_cursor(self.watchCursor)
        self.qQuery.put(newJob,True,10)

    def refresh_module_list(self):
        self.installedModules=self.get_installedModules()

        self.mainWindow.ModuleChooserMenu.destroy()
        self.mainWindow.ModuleChooserMenu=gtk.Menu()
        self.mainWindow.itemSubMenuModuleChooser.set_submenu(\
            self.mainWindow.ModuleChooserMenu)
        defaultModule=self.get_defaultModule()

        targetItem=False

        if not self.installedModules.keys():
            return
        
        for m in self.installedModules.keys():
            if m=="StrongsHebrew" or m=="StrongsGreek":
                continue
            
            cur=gtk.MenuItem(m)
            if m==defaultModule:
                targetItem=cur
            self.mainWindow.ModuleChooserMenu.append(cur)
            cur.connect_object("activate",self.moduleActivate,m)
            cur.show()

        if targetItem:
            targetItem.activate()
        else:
            cur.activate()

    def refresh_textArray(self):
       book=self.getInfoBasedOnAbbr(self.selected_book)
       self.textArray=[]
       bName=book['name']
       vk=Sword.VerseKey()
       markup=Sword.MarkupFilterMgr(Sword.FMT_PLAIN)
       markup.thisown=False
       mgr=swordutils.get_manager(markup)
       mod=mgr.getModule(self.selected_module)
       if not mod:
          return
       nbr_verses=vk.verseCount(book['testament'],\
                                book['bookCount'],self.selected_chapter)
       for i in range(nbr_verses):
          n=i+1
          key="%s %d:%d"%(bName,self.selected_chapter,n)
          vk=Sword.VerseKey(key)
          mod.setKey(vk)
          #verseTxt=mod.RenderText()
          mgr.setGlobalOption("Cross-references","Off")
          if self.showStrongNumbers:
              mgr.setGlobalOption("Strong's Numbers","On")
          else:
              mgr.setGlobalOption("Strong's Numbers","Off")
          verseTxt=mod.RenderText()

          if self.append_carriage_return:
              verseTxt.rstrip("\r")
              verseTxt.rstrip("\n")
              verseTxt=verseTxt+"\n"
              
          self.textArray.append(verseTxt)
          
       self.refreshTextDisplay()


    def scrollToSelected(self):
        mark=self.textDisplay_buffer.get_mark(str(self.selected_verse))
        if mark:
            self.textDisplay_textview.scroll_to_mark(mark,0.05, True, 0.0, 1.0)
        
    def refreshTextDisplay(self):
    	for mark in self.textMarks:
    	    if mark is not None and mark.get_buffer() is not None and mark.get_buffer().get_char_count() > 0:
                self.textDisplay_buffer.delete_mark(mark)
        self.textDisplay_buffer.set_text("")
        v=0
        for verse in self.textArray:
            v=v+1
            #versesnt="(%d) %s"%(v,verse)
            indicatorSnt="(%d) "%v
            verse_indicator_markLabel="indicator"+str(v)
            verse_begin_markLabel=str(v)
            #print verse_begin_markLabel
            verse_end_markLabel="end"+str(v)
            endIter=self.textDisplay_buffer.get_end_iter()
            indic_mark=self.textDisplay_buffer.create_mark(\
                verse_indicator_markLabel,endIter,left_gravity=True)
            self.textMarks.append(indic_mark)
            self.textDisplay_buffer.insert_with_tags(\
                endIter,indicatorSnt,self.indiceTag)
            begin_mark=self.textDisplay_buffer.create_mark(\
                verse_begin_markLabel,endIter,left_gravity=True)
            self.textMarks.append(begin_mark)
            if self.selected_verse==v:
                tmpTag=self.highlightTag
            else:
                tmpTag=self.normalTag
            self.textDisplay_buffer.insert_with_tags(endIter,verse,tmpTag)
            self.textMarks.append(\
                self.textDisplay_buffer.create_mark(\
                verse_end_markLabel,endIter,left_gravity=True))
            

        self.highlight_verse(self.selected_verse,self.highlightTag)
        self.scrollToSelected()
        
    def highlight_verse(self, verse,tag):
        if not verse:
            return
        beginMark=self.textDisplay_buffer.get_mark(str(verse))
        if not beginMark:
            print "no mark for verse ",verse
            return
        beginIter=self.textDisplay_buffer.get_iter_at_mark(beginMark)
        endMark=self.textDisplay_buffer.get_mark("end"+str(verse))
        endIter=self.textDisplay_buffer.get_iter_at_mark(endMark)

        self.textDisplay_buffer.apply_tag(tag,beginIter,endIter)
        #self.textDisplay_buffer.place_cursor(beginIter)
        
    def moduleActivate(self,moduleName):
        self.selected_module=moduleName
        self.mainWindow.set_title(moduleName)
        self.refresh_textArray()

        if swordutils.has_strong_number(self.mgr,moduleName):
            self.mainWindow.strong_number_item.show()
        else:
            self.showStrongNumbers=False
            self.mainWindow.strong_number_check_b.set_active(False)
            self.mainWindow.strong_number_item.hide()




    def book_combo_changed(self,widget):
        self.selected_book=self.get_combo_active_text(widget)
        self.fillChapters()
        
    def chapter_combo_changed(self,widget):
	if self.get_combo_active_text(widget) is not None:
            self.selected_chapter=int(self.get_combo_active_text(widget))
	    self.fillVerses()
        #self.refresh_textArray()

    def verse_combo_changed(self,widget):
        self.highlight_verse(self.selected_verse,self.normalTag)
        if self.get_combo_active_text(widget) is not None:
    	    self.selected_verse=int(self.get_combo_active_text(widget))
    	    self.refresh_textArray()
        """

        print "verse_combo_changed:",self.selected_verse
        print self.selected_verse
        #
        #mark.set_visible(True)
        self.highlight_verse(self.selected_verse,self.highlightTag)
        mark=self.textDisplay_buffer.get_mark(str(self.selected_verse))
        self.textDisplay_textview.scroll_to_mark(mark,0.05)
        """
    def display_b_clicked(self,widget):
        self.refresh_textArray()

    def search_b_clicked(self,widget):
        if not swordutils.has_clucene_index(self.mgr, self.selected_module)\
               and not self.showStrongNumbers:
            dialog = hildon.Note ("information", \
                                  self.mainWindow, \
                                   "You need to build an index for "+\
                                   "this module first.",\
                                   gtk.STOCK_DIALOG_INFO\
                                  )
                                  
                                  
#            dialog.set_button_text("Ok")
            dialog.run()
            dialog.destroy()
            return

        if self.showStrongNumbers and not self.strong_db:
            dialog = hildon.Note ("information", \
                                  self.mainWindow, \
                                   "You need to download a Strong Number "+\
                                   "database and change "+\
                                   "the Preferences to point to its "+\
                                   "location.\n"+\
                                   "Such a database is available at \n"+\
                                   
                                   "http://hurdygurdy.dyndns.org/maemosword/strong.zip",\
                                   gtk.STOCK_DIALOG_INFO\
                                  )
#            dialog.set_button_text("Ok")
            dialog.run()
            dialog.destroy()
            return
            
        
        filterSnt=self.searchEntry.get_text()
        args={'filter':filterSnt,'module':self.selected_module,\
              'useStrongNumber':self.showStrongNumbers,\
              'database':self.strong_db}
        self.searchProgressbar.show()
        self.waitForSearchFlag=True
        self.putJob(aJob(self.jobCounter,"search_string",args))
        self.clean_searchResult_TreeView()

    def back_b_clicked(self,widget):
        if self.selected_chapter>1:
            tmp=int(self.selected_chapter)-1
            self.mainWindow.chapter_tb_combo.set_active(tmp-1)
            self.refresh_textArray()

    def next_b_clicked(self,widget):
        if self.selected_chapter<self.maxChapter:
            self.mainWindow.chapter_tb_combo.set_active(self.selected_chapter)

    def strong_number_check_b_clicked(self,widget):
        self.showStrongNumbers= widget.get_active()
        self.refresh_textArray()

    def set_display_to_ref(self,ref):
        info=self.get_info_from_refs(ref)

        bIndex=0
        for i in self.booksInfo:
            if i['abbr']==info['abbr']:
                self.mainWindow.book_tb_combo.set_active(bIndex)
            bIndex+=1

        self.mainWindow.chapter_tb_combo.set_active(int(info['chapter'])-1)
        self.mainWindow.verse_tb_combo.set_active(int(info['verse'])-1)


    def result_selection_changed(self,selection):
        model,iter=selection.get_selected()
        if not iter:
            return
        id=self.result_ts.get_value(iter,1)
        if id:
            self.set_display_to_ref(id)
    
    def clean_searchResult_TreeView(self):
        self.result_ts.clear()
        try:
            for c in self.searchResult_TreeView.get_columns():
                self.searchResult_TreeView.remove_column(c)
        except:
            print "oups"

    def sort_books(self,model,iter1,iter2):
        """
         There is a need to sort result in the search tree view.
        """
        book1=model.get_value(iter1,0)
        long1=model.get_value(iter1,1)

        book2=model.get_value(iter2,0)
        long2=model.get_value(iter2,1)

        if (not long1 and long2) or (long1 and not long2):
            return 0

        if (not long1 and  not long2):
            """
            This is a book directory, not an actual content.
            Sorting according to book indice
            """
            #print "%s vs %s"%(book1,book2)
            info1=self.getInfoBasedOnAbbr(book1)
            info2=self.getInfoBasedOnAbbr(book2)
            if info1['testament']!=info2['testament']:
                return int(info1['testament']-info2['testament'])
            else:
                return int(info1['bookCount']-info2['bookCount'])
            print "this should not happen"

            return 1

            
        elif long1 and long2:
            """ This is 2 actual reference to be sorted"""
            
            info1=self.get_info_from_refs(long1)
            info2=self.get_info_from_refs(long2)

            if info1['abbr']!=info2['abbr']:
                print "How can this happen ???"
                return 0
            
            """so, we are sure we are in the same book"""
            if info1['chapter']==info2['chapter']:
                return int(info1['verse'])-int(int(info2['verse']))
            else:
                return int(info1['chapter'])-int(int(info2['chapter']))

            print book1,book2
            print "grumble, dont know how to sort that !"
            return 0


    def go_to_bookmark(self,position):
        """
        Set the page to display so it match position.
        position is like 'Gen 1:1'
        """
        infos=self.get_info_from_refs(position)
        cnt=0
        for i in self.booksInfo:
            if i['abbr']==infos['abbr']:
                self.mainWindow.book_tb_combo.set_active(cnt)
            cnt+=1

        for i in range(self.maxChapter):
            if int(i)==int(infos['chapter'])-1:
                self.mainWindow.chapter_tb_combo.set_active(i)

        for i in range(self.maxVerse):
            if int(i)==int(infos['verse'])-1:
                self.mainWindow.verse_tb_combo.set_active(i)


        self.refresh_textArray()
        self.scrollToSelected()


    def display_strong_info(self,afilter):
        afilter=string.upper(afilter)
        if afilter[0]=='G':
            tmpMod="StrongsGreek"
        else:
            tmpMod="StrongsHebrew"

        isInstalled=False
        
        for curMod in self.mgr.getModules().values():
            if tmpMod == curMod.Name():
                isInstalled=True

        if not isInstalled:
            return

        mod=self.mgr.getModule(tmpMod)
        mod.KeyText(afilter[1:])
        test=mod.RenderText()
        self.show_dic_window(mod.RenderText())
        
        


    def search_string(self,job):
        """ display the result of a search"""
        result=job.result
        self.searchProgressbar.hide()
        self.waitForSearchFlag=False


        if job.args['useStrongNumber']:
            self.display_strong_info(job.args['filter'])

        
        self.clean_searchResult_TreeView()
        #self.result_ts=gtk.TreeStore(str,str)
        self.result_ts.set_sort_func(0,self.sort_books)
        self.result_ts.set_sort_column_id(0,gtk.SORT_ASCENDING)
        self.searchResult_TreeView.set_model(self.result_ts)
        labelCell=gtk.CellRendererText()
        labelcol=gtk.TreeViewColumn('Ref')
        labelcol.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        self.searchResult_TreeView.append_column(labelcol)
        labelcol.pack_start(labelCell,True)
        labelcol.set_attributes(labelCell,text=0)
        books={}
        self.searchResult_TreeView.freeze_child_notify()
        for cur in result:
            info=self.get_info_from_refs(cur)
            if not books.has_key(info['abbr']):
                """First data for the abbr book"""
                books[info['abbr']]=self.result_ts.append(\
                    None,[info['abbr'],''])
            iter=books[info['abbr']]
            self.result_ts.append(iter,[cur,cur])



        self.searchResult_TreeView.thaw_child_notify()

        

    def processAnswer(self):
        """Handle all jobs currently in qOut, if any"""
        if self.waitForSearchFlag:
            self.searchProgressbar.pulse()
        if self.waitForRemoteModulesFlag:
            self.waitingWinProgressBar.pulse()
        if self.waitForModuleManagementFlag:
            self.waitingWinProgressBar.pulse()


        #textview motion update:
        adj=self.textDisplay_scrolledWindow.get_vadjustment()
        adjval=adj.get_value()
        if self.motion_adjust!=0:
            adj.set_value(adjval+self.motion_adjust)
            self.motion_adjust=0

            
        while self.qAnswer.qsize():
            curJob=self.qAnswer.get(0)
            if curJob.type=="idle":
                return True
            elif curJob.type=="search_string":
                self.search_string(curJob)
                return True
            elif curJob.type=="remote_modules_list":
                self.refresh_remote_modules(curJob.result)
                return True
            elif curJob.type=="module_management":
                self.process_module_management(curJob.result)
                return True
            elif curJob.type=="panic":
                self.process_panic(curJob)
                return True
            elif curJob.type=="iowaitmsg":
                return True
            else:
                print "Cannot process this kind of answer:"
                print curJob.id
                print curJob.type
                #print curJob.args
        return True

class ThreadedClient:
    """
    This class launch the GuiPart and the worker thread.
    """

    def __init__(self):
        """
        This start the gui in a asynchronous thread.
        We are in the "main" thread of the application, wich will later be
        used by the gui as well. We spawn a new thread for the worker.
        
        """
        #gtk.threads_init()
        gtk.gdk.threads_init()
        self.qQuery=Queue.Queue()
        self.qAnswer=Queue.Queue()
        self.gui=GuiPart(self.qQuery,self.qAnswer)
        self.running=True
        #self.mgr=Sword.SWMgr() 
        self.incomingThread=threading.Thread(target=self.processQuery)
        self.incomingThread.setDaemon(True)
        self.incomingThread.start()
        gtk.main()
        self.running=False
       
    def search_string(self,args):
        out=[]

        useStrong=args['useStrongNumber']
        markup=Sword.MarkupFilterMgr(Sword.FMT_PLAIN)
        markup.thisown=False
        mgr=swordutils.get_manager(markup)
        mod=mgr.getModule(args['module'])
        if not useStrong:
            res=mod.doSearch(args['filter'],-4)
            for n in range(res.Count()):
                vk=res.GetElement(n)
                out.append(vk.getShortText())
            return out
        else:
            db=sqlite3.connect(args['database'])
            c=db.cursor()
            for row in \
                c.execute("select verse from  Words_Per_Verse where word=?",\
                      (string.upper(args['filter']),)):
                out.append(row[0])
            return out

    def remote_modules_list(self,args):
        data_path = args['data_path']
        tmp=swordutils.InstallMgr(dataPath=data_path,
                                  osso_context=args['osso_context'])
        return tmp.get_remote_modules_list()

    def module_management(self,args):
        #print "args=",args
        problems=False
        data_path = args['data_path']
        instmgr=swordutils.InstallMgr(dataPath=data_path,
                                      osso_context=args['osso_context'])
        for mod in args['mod_remove']:
            swordutils.debug("let s remove '%s'"%mod)
            if not instmgr.remove_module(mod):
                problems=True
        for mod in args['install']:
            remoteM={}
            for r in args['remote']:
                if r['Name']==mod:
                    remoteM=r
            swordutils.debug("let's install %s"%mod)
            swordutils.debug("dataPath=%s"%remoteM['DataPath'])
            swordutils.debug("conf file=%s"%remoteM['conf_file_name'])
            if not instmgr.install_module(remoteM['DataPath'],
                                          remoteM['conf_file_name']):
                swordutils.debug("Installing %s failed"%mod) 
                problems=True
            else:
                swordutils.debug("%s module installation is ok"%mod)
            
        for idx in args['idx_remove']:
            swordutils.debug("let's remove '%s' "%idx)
            if not instmgr.remove_index(idx):
                swordutils.debug("Removing %s failed"%idx)
                problems=True
        for idx in args['idx_build']:
            swordutils.debug("let's create index for %s"%idx)
            if not instmgr.create_index(idx):
                swordutils.debug("Creating index for %s failed"%idx)
                problems=True
        return problems
        
    def processQuery(self):
       """
       This is where the blocking I/O job is being done.
       """

       while self.running:
           while self.qQuery.qsize():
               try:
                   job=self.qQuery.get(False,40)
                   job.result='we would store the resutl here'
                   ioWaitMsg=aJob(0,'iowaitmsg',\
                                  {'jobid':job.id,'type':job.type})
                   self.qAnswer.put(ioWaitMsg)
                   if job.type=="search_string":
                       job.result=self.search_string(job.args)
                   elif job.type=="remote_modules_list":
                       job.result=self.remote_modules_list(job.args)
                   elif job.type=="module_management":
                       job.result=self.module_management(job.args)
                   else:
                       swordutils.debug(\
                           "Cannot cope with this kind of job:%s"%job.type)
                       print "Cannot cope with this kind of job:"
                       print job.id
                       print job.type
                       print job.args
                   self.qAnswer.put(job)
               except Queue.Empty:
                   print "Queue should not be empty"
                   pass
               except:
                   print "ke passa ?"
                   swordutils.debug('Ke passa ?')
                   swordutils.debug(\
                       "Yet another unexpected error:%s"%sys.exc_info()[0]
                       )
                   quitJob=aJob(0,"panic",{"message":sys.exc_info()[0]})
                   self.qAnswer.put(quitJob)
                   sys.exit()
               
           self.gui.currentJobId=None
           idlMsg=aJob(0,'idle',{})
           self.qAnswer.put(idlMsg)
           time.sleep(1)

if __name__=="__main__":
    plop=ThreadedClient()
    
