# you really want to read the templates.py files before
# hacking this file

from copy import copy
import sys

if not sys.modules.has_key('gtk'):
    import pygtk
    pygtk.require('1.2')

from gtk import *
import GtkExtra
import string
import os

from specific import *
from entry_classes import *
import joins
import log
import checks

################ row widgets


class select_navigate_widget:
    "provides facility for doing a SELECT and for navigating it"

    __cursor=None
    #easy type-in key
    __easyselect_key=None

    #button_next button_prev may be accessed from outside
    def __init__(self):  
        hbox=GtkHBox()
        self.widget=hbox
        self.__widget=hbox
        
        hbox.show()

        prev=GtkButton()
        a=GtkArrow(ARROW_LEFT, SHADOW_OUT)
        a.show()
        prev.add(a)
        prev.show()
        hbox.pack_start(prev, FALSE, FALSE, 2)
        #this may be overridden
        prev.connect("clicked", self.cursor_prev)
        self.button_prev=prev
        
        next=GtkButton()
        a=GtkArrow(ARROW_RIGHT, SHADOW_OUT)
        a.show()
        next.add(a)
        next.show()
        hbox.pack_start(next, FALSE, FALSE, 2)
        #this may be overridden
        next.connect("clicked", self.cursor_next)
        self.button_next=next

        button_=GtkButton("select where")
        button_.show()
        hbox.pack_start(button_, FALSE, FALSE, 2)
        button_.set_flags(CAN_FOCUS)
        self.button_select=button_
        button_.connect("clicked",self.select)
                         
        self.__entry_where=GtkEntry()
        hbox.pack_start(self.__entry_where, TRUE, TRUE, 2)
        self.__entry_where.show()
        self.__entry_where.set_flags(CAN_FOCUS)
        self.__entry_where.connect("activate",self.select)

        l=GtkButton()
        self.__easyselect_button=l
        hbox.pack_start(l,FALSE, FALSE, 2)
        l.show()
        self.__lbes=GtkLabel('')
        self.__lbes.show()
        l.add(self.__lbes)
                
        self.__entry_key=GtkEntry()
        self.__entry_key.connect("activate", self.select)
        #FIXME this is not in 'characters':self.entry_key.set_usize(80,10)
        hbox.pack_start(self.__entry_key,FALSE, FALSE, 2)


        mf = GtkExtra.MenuFactory()        
        z=[('?/-',None,self.easyselect_set,None)]
        for i in self.fields:
            z.append(('?/'+i,None,self.easyselect_set,i))
            if self.field_join.has_key(i) :
                (t2,f2)=self.field_join[i]
                for j in self.field_entry[i].fields :
                    z.append(('?/'+i+'.../'+j,None,
                              self.easyselect_set,t2+'/'+f2+'/'+i+'/'+j))
        mf.add_entries(z)
        mf.show()
        hbox.pack_start(mf,FALSE, FALSE,2)

        l.connect("clicked",self.easyselect_set,None)

    
    def reset(self):
        self.__widget.set_sensitive(TRUE)
        self.__entry_key.set_text('')
        self.__entry_where.set_text('')
        self.easyselect_set(None,None)

    
    def easyselect_get(self):
        "gets easy key"
        #if self.__easyselect_key==None:            
        #    return None
        #else:
        return self.__easyselect_key

    def easyselect_set_text(self,key):
        self.__entry_key.set_text(key)
    
    def easyselect_set(self,button,i):
        "sets easy key"
        try:
            if i != None and type(1) == type(i):
                i=self.fields.index(i)
        except:
            self.log(log.LOG_WARNING, "UNKNOWN RECORD "+str(i))
            return
        self.__easyselect_key=i
        self.__easyselect_button.remove(self.__lbes)
        if i!=None:
            if '/' in self.__easyselect_key:
                a=string.split(self.__easyselect_key,'/')
                l=GtkLabel('&& '+a[0]+'/'+a[3] +" LIKE")
            else:
                l=GtkLabel('&& '+self.__easyselect_key+" LIKE")
            self.__entry_key.show()
            self.__easyselect_button.show()
        else:
            l=GtkLabel("...")
            self.__entry_key.hide()
            self.__easyselect_button.hide()
        self.__lbes=l
        l.show()
        self.__easyselect_button.add(l)
            
    #useful methods to use the cursor in a consistent way

    def select(self,button):
        self.cursor_del()
        #FIXME THIS DOESNT WORK
        #sql="SELECT ("+self.keyfield+", id) FROM " + self.table_name
        sql="SELECT " + self.table_name + ".* FROM " + self.table_name
        
        #if button:
        #    logging=self.log
        #else:
        #    logging=lambda *x: None

        selkey=self.__entry_key.get_text()
        selwhere=self.__entry_where.get_text()
        where=" WHERE "
        if selkey != "" and self.__easyselect_key!=None:
            if '/' in self.__easyselect_key:
                a=string.split(self.__easyselect_key,'/')
                sql=sql +','+a[0]+' '+where+\
                     a[0]+'.'+a[1]+' = '+self.table_name+'.'+a[2]+\
                     ' && '+a[0]+'.'+a[3] + " LIKE '"+selkey+"%' "
                where=' && '
            else:
                sql=sql +where+ self.__easyselect_key + " LIKE '"+selkey+"%' "
                where=' && '
        if selwhere:
            sql=sql +where+ selwhere
            where=' && '
        #if selkey != "" and self.__easyselect_key!=None:
        #    sql=sql+" ORDER BY "+self.fields[self.__easyselect_key]
        result=self.cursor_query(sql)
        if result:
            r=self.cursor_next(None)
            if not r:
                self.log(log.LOG_ERROR,"no matching line for:" +sql)
                self.cursor_del()
            else:
                if button or result == 1:
                    self.log(log.LOG_INFO,"%d matches in %s" %
                             (result,self.table_name))                    
                else:
                    #if this is an automatic search, it should return 1 result
                    self.log(log.LOG_WARNING,"%d matches in %s" %
                             (result,self.table_name))
        else:
            self.log(log.LOG_ERROR,"no matches for:" +sql)
            self.cursor_del()
            
    def has_cursor(self):
        return not not self.__cursor
    
    def cursor_query(self,query):
        #prepares the cursor for a SELECT query
        if self.__cursor:
            del self.__cursor
            
        self.__cursor=self.db.cursor()
        if self.__cursor == None:
            self.log(log.LOG_ERROR, "E: could not get a cursor (please retry)")
            return 0
                   
        self.log(log.LOG_SQL, "SQL :"+query)

        try:            
            self.__cursor.execute(query)
        except self.dbapi_exceptions.Warning, a:
            self.log(log.LOG_WARNING,"WARNING: "+str(a))
            self.__cursor=None
            return 0
        except self.dbapi_exceptions.Error, a:
            self.log(log.LOG_ERROR,"ERROR: "+str(a))
            self.__cursor=None
            return 0
        else:
            self.__cursor.backlist=[]
            self.__cursor.position=-1
            return self.__cursor.rowcount
        
    def cursor_next(self,b):
        if len(self.__cursor.backlist) > self.__cursor.position+1:
            self.__cursor.position = 1 + self.__cursor.position
            r=self.__cursor.backlist[self.__cursor.position]
        else:
            r=self.__cursor.fetchone()
            if r:
               self.__cursor.backlist.append(r)
               self.__cursor.position = 1 + self.__cursor.position
        if r:
            self.set_row(r)
        else:
            #if called from a button...
            if b:
                self.log(log.LOG_MESSAGE,"no more matches")
            self.set_row(None)
            #self.cursor=None
        self.button_next.set_sensitive(not not r)
        self.button_prev.set_sensitive(self.__cursor.position>0)
        #print "NEXT"+str(self.__cursor.position)
        return r

    def cursor_prev(self,b):
        if self.__cursor.position>0:
            self.__cursor.position = self.__cursor.position - 1
        else:        
            self.log(log.LOG_MESSAGE,"already on first row")        
        r=self.__cursor.backlist[self.__cursor.position]
        self.set_row(r)
        self.button_prev.set_sensitive(self.__cursor.position>0)
        self.button_next.set_sensitive(TRUE)
        #print "PREV"+str(self.__cursor.position)
        return r

    def cursor_del(self):
        if self.__cursor:
            del self.__cursor
            self.__cursor=None
        self.button_next.set_sensitive(FALSE)
        self.button_prev.set_sensitive(FALSE)


    
class fast_search_widget(table_info,row_widget_template,
                         select_navigate_widget):
    __row=None
    __popup_window=None
    __primary_value=None
    __n_primary=None
    def __init__(self,db,db_name,table_name,
                 #which field to use to select when doing set() or get()
                 join_field=None ):

        table_info.__init__(self,db,db_name,table_name)        
        row_widget_template.__init__(self)

        if join_field != None:
            self.__n_primary=self.fields.index(join_field)

        select_navigate_widget.__init__(self)
        #save it for future references
        self.select_navigate_thewidget=self.widget


        self.db_name=db_name
        self.table_name=table_name
        self.db=db

        #main widget
        vbox=GtkVBox()

        hbox=GtkHBox()
        hbox.show()

        self.label_current=GtkEntry()
        self.label_current.set_editable(FALSE)
        #self.label_current.set_sensitive(FALSE)
        self.label_current.show()
        #self.label_current.set_justify(JUSTIFY_RIGHT)
        #self.label_current.set_position(0)
        hbox.pack_start(self.label_current, TRUE, TRUE, 2)

        arr=GtkArrow(ARROW_UP, SHADOW_OUT)
        arr.show()
        b=GtkButton()
        b.add(arr)
        b.show()
        #b.add(self.label_current)
        b.connect("pressed",self.__popup)
        b.connect("released",self.__popdown)

        hbox.pack_start(b, FALSE, FALSE, 2)
        
        vbox.pack_start(hbox, TRUE, TRUE, 2)
        
        vbox.pack_start(self.select_navigate_thewidget, FALSE, FALSE, 2)

        vbox.show()
        self.widget=vbox
        self.__widget=vbox

    def __popup(self,b):
        if self.__row==None:
            return
        if not self.__popup_window:    
            f=form_widget(self.db,self.db_name,self.table_name)
            f.set_editable(FALSE)
            self.__popup_form=f
            window1=GtkWindow(WINDOW_POPUP)
            window1.set_policy(FALSE, TRUE, FALSE)
            window1.add(f.widget)
            window1.set_position(WIN_POS_MOUSE)
            self.__popup_window=window1
        self.__popup_window.show()
        self.__popup_form.set_row(self.__row)
        
    def __popdown(self,b):
        if self.__popup_window:
            self.__popup_window.hide()
            
        
    def get(self):
        return self.__primary_value
    
    def set(self,data):
        self.cursor_del()
        #whatever it is... save it!
        self.__primary_value=data
        
        if self.__n_primary == None:
            self.log(log.LOG_ERROR,'INTERNAL ERROR: cant "set" into table ' + self.table_name)
        if data != None:
            sql="SELECT * FROM " + self.table_name +\
                " WHERE " + self.fields[self.__n_primary] +   " = "+str(data)
            cursor=self.db.cursor()
            #self.log(log.LOG_SQL,repr(sql))
            cursor.execute(sql)        
            self.set_row(cursor.fetchone())
            del cursor
        else:
            self.set_row(None)


    def set_row(self,r):
        self.__row=r
        if r != None:
            if self.__n_primary:
                self.__primary_value=r[self.__n_primary]
            self.label_current.set_text(str(r))
            self.label_current.set_position(0)
        else:
            #FIXME: is this the right thing to do?
            self.__primary_value=None
            self.label_current.set_text("NULL")
            select_navigate_widget.reset(self)
            
    def get_row(self):
        return self.__row
    
    def set_editable(self,v):        
        self.select_navigate_thewidget.set_sensitive(v)            
        #self.select_navigate.set_editable(v)




        
class form_widget(table_info,row_widget_template):
    __current_row=None
    
    def __init__(self,db,db_name,table_name,
                 #these are used for automatic joins
                 join_rules=[],table_fields={}):

        table_info.__init__(self,db,db_name,table_name)
        row_widget_template.__init__(self)

        self.__table_name=table_name
        
        frame=GtkFrame(table_name)
        frame.show()

       #export this
        self.widget=frame
        #and keep a copy
        self.__widget=frame
        
        vbox2=GtkVBox()
        vbox2.show()
        
        frame.add(vbox2)

 
        ########fields
        for f in self.fields:
            columninfo=self.field_columninfo[f]
            description=self.field_description[f]
            (Field, Type, Null, Key, Default, Extra) = columninfo

            hbox1=GtkHBox()
            vbox2.pack_start(hbox1, FALSE, TRUE, 0)
            #hbox1.set_usize(-1, -1)
            hbox1.set_homogeneous(FALSE)
            hbox1.set_spacing(0)

            eventbox1=GtkEventBox()
            hbox1.pack_start(eventbox1, FALSE, FALSE, 0)
            #eventbox1.set_usize(-1, -1)
            label1=GtkLabel()
            eventbox1.add(label1)
            tooltip = GtkTooltips();
            tup=''
            lists=map(None,
                      ('Field', 'Type', 'Null', 'Key', 'Default', 'Extra'),
                      columninfo)+\
                      map(None,
                          ('name', 'type_code', 'display_size', 'internal_size', 'precision', 'scale', 'null_ok'),
                          description)
            for (a,b) in lists:
                tup=tup+str(a)+'='+str(b)+'\n'
            tooltip.set_tip(eventbox1,tup)
            eventbox1.show()

            label1.set_justify(JUSTIFY_CENTER)
            label1.set_alignment(0.5, 0.5)
            label1.set_padding(0, 0)
            label1.show()

            join=None
            if join_rules != []:
                join=joins.find_join(self.table_name, Field,
                                     #these are used for automatic joins
                                     join_rules,table_fields)
            if join != None:
                (t2, f2)=join
                #print "join " + repr(join)
                entry1=fast_search_widget(self.db,self.db_name,t2,f2)
                entry1.dbapi_exceptions=self.dbapi_exceptions
                self.field_join[Field]=(t2,f2)
                self.join_field[t2]=Field
                label1.set_text(Field+'=\n='+t2+'.'+f2)
            else:
                label1.set_text(Field)
                entry1=appropriate_entry_widget(columninfo,description)
            #redirect log messages                
            entry1.log=self.log
            hbox1.pack_start(entry1.widget, TRUE, TRUE, 0)
            hbox1.show()
            self.field_entry[Field]=entry1

    #template methods
    def set_editable(self,v):
        for f in self.fields:
            e=self.field_entry[f]
            #print 'self.primary_key_fields'+str(self.primary_key_fields)
            if f in self.primary_key_fields:
                #e.entry_widget
                e.set_editable(FALSE)
            else:
                #e.entry_widget
                e.set_editable(v)
                
    def get_row(self):
        r=[]
        for i in range(self.n_fields):
            entry=self.field_entry[ self.fields[i] ]
            r.append(entry.get())
        return r
    
    def get_current_row(self):
        """this is the row that was set into this class, not the one that the
        user edits"""
        return self.__current_row

    def set_row(self,row):
        if row != None:
            for i in  range(len(row)):
                entry=self.field_entry[ self.fields[i] ]
                entry.set(row[i])
                self.__current_row=copy(row)
        #else:
        #    self.log(1,"Can't set row to None in form for table "+self.__table_name)






class editor_widget(form_widget, select_navigate_widget):
    def __init__(self,db,db_name,table_name,
                 #api
                 dbapi,dbapi_exceptions,
                 #if there is an extra main widget for loggin, we call it with
                 main_log=None,
                 #these are used for automatic joins
                 join_rules=[],table_fields={},
                 #list of functions that will check the row (see checks.py)
                 checks=[checks.extra_spaces,checks.empty_null,
                         checks.not_null_not_empty]):
        
        self.dbapi_exceptions=dbapi_exceptions        
        self.checks=checks

        ###the log widget (it is in log.py)
        #log.log_widget.__init__(self)
        #self.log=logwidget.log
        #use it also for the form widget
        #formwidget.log=logwidget.log
        ##save it for future references
        #
        self.logger=log.log_widget(main_log)
        self.log_thewidget=self.logger.widget
        self.log=self.logger.log
        
        ###the form widget
        form_widget.__init__(self,db,db_name,table_name,
                             #these are used for automatic joins
                             join_rules,table_fields)
        #save it for future references
        formwidget=self.widget

        ### the select navigate widget
        select_navigate_widget.__init__(self)
        #save it for future references
        self.select_navigate_thewidget=self.widget

        
        vbox1=GtkVBox()

        vbox1.set_spacing(2)

        
        #hbox4=GtkHBox()
        handlebox=GtkHandleBox()
        vbox1.pack_start(handlebox, FALSE, FALSE, 2)
        handlebox.show()

        vbox4=GtkVBox()
        handlebox.add(vbox4)
        vbox4.show()

        ### toolbar of buttons
        tb=GtkToolbar()
        tb.show()
        tb.set_space_style(TOOLBAR_SPACE_LINE)
        tb.set_space_size(20)
        
        vbox4.pack_start(tb,FALSE,FALSE,2)



        button_=GtkButton("insert")
        tb.append_widget(button_, "insert the record","")
        button_.show()
        button_.set_flags(CAN_FOCUS)
        self.button_insert=button_
        self.button_insert.connect("clicked",self.insert)
                         
        button_=GtkButton("new")
        button_.show()
        tb.append_widget(button_, "reset and edit","")
        button_.set_flags(CAN_FOCUS)
        self.button_new=button_
        button_.show()                
        self.button_new.connect("clicked",self.new)
                         
        button_=GtkButton("edit")
        button_.show()
        tb.append_widget(button_, "edit this record","")
        button_.set_flags(CAN_FOCUS)
        self.button_edit=button_
        button_.show()                
        self.button_edit.connect("clicked",self.edit)
                         
        button_=GtkButton("update")
        button_.show()
        tb.append_widget(button_, "update the edited record to the new values","")
        button_.set_flags(CAN_FOCUS)
        self.button_update=button_
        self.button_update.connect("clicked",self.update)

        button_=GtkButton("cancel")
        button_.show()
        tb.append_widget(button_, "","")
        button_.set_flags(CAN_FOCUS)
        #button_.show()
        self.button_cancel=button_
        self.button_cancel.connect("clicked",self.cancel)

        tb.append_space()

        button_=GtkButton("delete")
        button_.show()
        tb.append_widget(button_, "","")
        button_.set_flags(CAN_FOCUS)
        #button_.show()
        self.button_delete=button_
        self.button_delete.connect("clicked",self.delete)

        tb.append_space()

        button_=GtkButton("default")
        button_.show()
        tb.append_widget(button_, "sets entry to default values","")
        button_.set_flags(CAN_FOCUS)
        #button_.show()
        self.button_default=button_
        self.button_default.connect("clicked",self.default)

        tb.append_space()

        button_=GtkButton("reset")
        tb.append_widget(button_, "returns this program to the starting state","")
        button_.set_flags(CAN_FOCUS)
        button_.show()
        self.button_reset=button_
        self.button_reset.connect("clicked",self.reset)

        tb.append_space()

        mf = GtkExtra.MenuFactory()
        mf.add_entries([
            ('Form/Save template', None,  self.gtk_form_save),
            ('Form/Load form',       None,         self.gtk_form_load),
            ('Form/Paste form',       None,         self.gtk_form_paste)
            ])
        # activate key bindings ...
        #self.add_accel_group(mf.accelerator)
        #self.mf = mf
        #returnmf
        mf.show()
        tb.append_widget(mf,"","")

        vbox4.pack_start(self.select_navigate_thewidget, FALSE,FALSE, 2)


        ###select stuff
        hbox=GtkHBox()        
        vbox4.pack_start(hbox, FALSE,FALSE, 2)
        hbox.show()

        #so we can show/hide
        self.widget_select=hbox

        #self.button_prev.set_size_request(20,20)
        #self.button_next.set_size_request(20,20)

        #add another callback
        self.button_prev.connect("clicked", self.editable)

        self.button_next.connect("clicked", self.editable)


        vbox1.pack_start(formwidget, TRUE, TRUE, 2)


        #the log widget (it is in log.py)
        vbox1.pack_start(self.log_thewidget, TRUE, TRUE, 2)

        vbox1.show()
        #export this
        self.widget=vbox1
        #and keep a copy
        self.__widget=vbox1

        #bring to initial state
        self.reset(None)

    ##############################
    def gtk_form_save(self,mi=None):
        fname = GtkExtra.file_open_box(modal=FALSE)
        if not fname: return        
        z=open(fname,'w')
        z.write("""################################################
##This form has been automatically generated.
##Lines starting with ## are comments, that are ignored
##Lines starting with the keyword  [[name]]=
##should be filled; you may write a paragraph following the keyword
##Please do not change what is inside the square brackets [[]]
""")
        self.form_save(z,[])
        z.write('[[END]]\n')
        z.close()

    def gtk_form_load(self,mi=None):
        fname = GtkExtra.file_open_box(modal=FALSE)
        if not fname: return        
        z=open(fname)
        self.__gtk_form_load(z)
        z.close()
        
    def gtk_form_paste(self,mi=None):
        #FIXME this is crude 
        t=GtkText()
        t.set_editable(TRUE)
        t.show()
        w=GtkWindow(WINDOW_TOPLEVEL)
        w.show()
        w.add(t)
        while events_pending():
            mainiteration()
        t.paste_clipboard()
        while events_pending() or  t.get_length() == 0 :
            mainiteration()
        ### this blocks
        #(i,o)=os.pipe()
        #z=os.fdopen(i,'r')
        #q=os.fdopen(o,'w')

        n='.sql-editor.stupidfile.'+str(os.getpid())
        q=open(n,'w')
        
        BLOCK_SIZE = 2048
        length = t.get_length()
        pos = 0
        while pos < length:
            buf = t.get_chars(pos,  min(pos+BLOCK_SIZE, length))
            if buf != None:
                q.write(buf)
            pos = pos + BLOCK_SIZE
        q.flush()
        q.close()
	
	z=open(n)
        self.__gtk_form_load(z)
        z.close()
	
        #os.close(i)
        #os.close(o)
	os.remove(n)
	w.destroy()
        while events_pending():
            mainiteration()
    def __DTE(self,DTE,content):
        zz=self.insert_DTE(DTE,string.replace(content,'\t','    '))
        if zz:
            (t,e)=zz
            if self.join_field.has_key(t):
                ff=self.join_field[t]
                hh=self.field_entry[ff]
                if hh.easyselect_get() == None:
                    self.log(log.LOG_VERBOSE,
                             'making '+str(zz)+' your current select key')
                    hh.easyselect_set(None,e)
                if hh.easyselect_get() == e:
                    self.log(log.LOG_VERBOSE,
                             'good '+str(zz)+' is your current select key')
                    hh.easyselect_set_text(string.replace(content[:-1],'\t\n\r','%%%'))
                    hh.select(None)
                else:
                    self.log(log.LOG_VERBOSE,
                             'sorry '+str(zz)+' is not your current select key')
            else:
                self.log(log.LOG_VERBOSE,
                         'sorry '+str(zz)+' is not a join')
    def __gtk_form_load(self,z):
        self.new(None)
        a=1
        DTE=None
        content=''
        while a:
            a=z.readline()
            if a[:5] == '[[END]]':
                break
            if a[:2] == '##':
                continue
            if a[:2] == '[[':
                #check line
                try:
                    l=a.index(']')
                except:
                    self.log(log.LOG_WARNING,  'Malformed form line '+a)
                    continue
                if len(a) <= l or a[l+1] != ']':
                    self.log(log.LOG_WARNING, 'Malformed form line '+a)
                    continue
                #insert this DTE if the next is different
                # otherwise it will join the values
                if DTE and DTE != a[2:l] :
                    zz=self.__DTE(DTE,content)
                    content=''
                DTE=a[2:l]
                a=a[l+2:]
                if a and a[0] == '=':
                    a=a[1:]
                if a and a[0] == ' ':
                    a=a[1:]
                content=content+a
                if content == '\n':
                    content=''
            else:
                content=content+a
        if DTE and content and DTE[:7] != '[[END]]' and DTE != 'END' :
            self.__DTE(DTE,content)
            content=''

    ############################
    def new(self,button):
        self.reset(None)
        self.edit(None)
        
    def edit(self,button):
        self.set_editable(TRUE)
        #we can update iff we have a (reasonable) row to update
        r=self.get_current_row()
        self.button_update.set_sensitive( r and  self.default_row != r)

        self.button_insert.set_sensitive(TRUE)
        self.button_default.set_sensitive(TRUE)
        self.button_cancel.set_sensitive(TRUE)
        
        self.button_delete.set_sensitive(FALSE)
        self.button_next.set_sensitive(FALSE)
        self.button_prev.set_sensitive(FALSE)

        self.button_edit.set_sensitive(FALSE)
        #self.button_select.set_sensitive(FALSE)
        #self.entry_select.set_sensitive(FALSE)
        self.select_navigate_thewidget.set_sensitive(FALSE)
        
    def default(self,button):        
        self.set_row(self.default_row)

    def editable(self,button):
        'can use edit button'
        r=self.get_row()
        if r:
            self.button_edit.set_sensitive(not self.n_primary or
                None != r[self.n_primary])        


    def delete(self,b):
        if len(self.primary_key_fields) != 1:
            self.log(log.LOG_ERROR,'sorry!  a record can be deleted only if the table has an unique primary key')
            return

        sql="DELETE FROM %s WHERE "  % self.table_name
        
        cr=self.get_current_row()

        if cr[self.n_primary] == None:
            self.log(log.LOG_WARNING,'cannot delete a null record')
            return
        
        sql=sql+self.fields[self.n_primary]+ "=%s LIMIT 1"
        longrow=(cr[self.n_primary])
        c=self.db.cursor()
        try:
            self.log(log.LOG_SQL,sql+'\n'+repr(longrow))
            try:
                c.execute(sql, longrow )
            except self.dbapi_exceptions.Warning, b:
                self.log(log.LOG_WARNING,"\nSQL WARNING:"+str(b))
        except self.dbapi_exceptions.Error, b:
            self.log(log.LOG_ERROR,"ERROR: "+str(b))
        else:          
            #self.set_row(r)
            #simple hack to show the new line
            self.reset(None)
            if  c.rowcount == 1:
                self.log(log.LOG_DONE,"delete was succesfull")
                self.reset(None)
            else:
                self.log(log.LOG_ERROR,"delete was done on %s rows" % c.rowcount )
        del c
        
            
    def update(self,b):
        r= self.get_row()
        (r, msgs,msg) = checks.check_list_of_checks(self.checks,self,r)        
        if r == None:
            self.log(log.LOG_ERROR,msg)
            return
        if msg:
            self.log(log.LOG_WARNING,msg)
        
        sql="UPDATE %s SET "  % self.table_name
        for i in range(self.n_fields):
            sql=sql+self.fields[i]+"=%s, "
        sql=sql[:-2]+" WHERE "

        cr=self.get_current_row()
        
        #FIXME: horrible fix for strange "cant update" problem
        if len(self.primary_key_fields)==1:            
            if cr[self.n_primary] == None:
                self.log(log.LOG_WARNING,'cannot update a record when the primary key value is NULL')
                return

            sql=sql+self.fields[self.n_primary]+ "=%s && "
            longrow=tuple(list(r) + [cr[self.n_primary]] )
        else:
            # this should work perfectly... but it does not!
            for i in range(self.n_fields):
                sql=sql+self.fields[i]+ "=%s && "
            longrow=tuple(list(r) + list(cr))
        #remove trailing ' && '
        sql=sql[:-4]
        
        #WHAT THE HELL IS WRONG
        #print "R " + repr (r)
        #print "CR " + repr(cr)
        #print "SQL " + repr(sql)

        self.db.select_db(self.db_name)
        self.db.paramstyle='format'
        c=self.db.cursor()
        try:
            self.log(log.LOG_SQL,sql+'\n'+repr(longrow))
            try:
                c.execute(sql, longrow )
            except self.dbapi_exceptions.Warning, b:
                self.log(log.LOG_WARNING,"\nSQL WARNING:"+str(b))
        except self.dbapi_exceptions.Error, b:
            self.log(log.LOG_ERROR,"ERROR: "+str(b))
        else:          
            self.set_row(r)
            #simple hack to show the new line
            self.cancel(None)
            if  c.rowcount == 1:
                self.log(log.LOG_DONE,"update was succesfull")
            else:
                self.log(log.LOG_ERROR,"update was done on %s rows" % c.rowcount )
        del c
        
    def insert(self,bla):
        r= self.get_row()
        if len(self.primary_key_fields) == 1 and r[self.n_primary] != None \
               and r[self.n_primary] != '':
            self.log(log.LOG_WARNING,'cannot insert a record when the primary key value is not NULL')
            return

        (r, msgs,msg) = checks.check_list_of_checks(self.checks,self,r)
        if r == None:
            self.log(log.LOG_ERROR,msg)
            return
        if msg:
            self.log(log.LOG_WARNING,msg)

        
        self.db.select_db(self.db_name)
        sql= "INSERT INTO " + self.table_name + " VALUES ( " + " %s, " *  (self.n_fields-1) + "%s )"
                
        
        self.db.select_db(self.db_name)
        self.db.paramstyle='format'
        c=self.db.cursor()

        self.log(log.LOG_SQL,sql+'\n'+repr(r))
        try:
            c.execute(sql ,  r)
        except self.dbapi_exceptions.Warning, b:
            self.log(log.LOG_WARNING,"SQL WARNING: " + str(b))
        except self.dbapi_exceptions.Error, b:
            self.log(log.LOG_ERROR,"SQL ERROR: " + str(b))
        else:
            self.log(log.LOG_DONE,"INSERT was succeful")
        del c

    def reset(self, bla):
        self.set_row(self.default_row)

        select_navigate_widget.reset(self)
        #_thewidget.set_sensitive(TRUE)
        
        self.set_editable(FALSE)
        self.cursor_del()

        self.button_prev.set_sensitive(FALSE)
        self.button_next.set_sensitive(FALSE)

        self.button_update.set_sensitive(FALSE)
        self.button_edit.set_sensitive(TRUE)
        self.button_new.set_sensitive(TRUE)
        self.button_insert.set_sensitive(FALSE)
        self.button_delete.set_sensitive(len(self.primary_key_fields) == 1)
        
        self.button_cancel.set_sensitive(FALSE)

        #self.log(0,"TABLE "+self.table_name)


    def cancel(self,button):            
        self.button_next.set_sensitive(self.has_cursor() )
        self.button_prev.set_sensitive(self.has_cursor() )
        self.select_navigate_thewidget.set_sensitive( self.has_cursor() )
        
        self.button_edit.set_sensitive(TRUE)        
        
        self.set_editable(FALSE)
        self.set_row(self.get_current_row())
        self.button_update.set_sensitive(FALSE)
        self.button_insert.set_sensitive(FALSE)
        self.button_cancel.set_sensitive(FALSE)

        


def editor(db, db_name, table_name,
           #api
           dbapi,dbapi_exceptions,
           #extra log
           main_log=None,
           #these are used for automatic joins
           join_rules=[],table_fields={}):
    x=editor_widget(db, db_name, table_name,
                    #api
                    dbapi,dbapi_exceptions,
                    #log
                    main_log,
                    #
                    join_rules, table_fields)

    window1=GtkWindow(WINDOW_TOPLEVEL)
    window1.set_title("sql:/"+db_name+"/"+table_name)
    #window1.set_usize(-1, -1)
    window1.set_policy(FALSE, TRUE, FALSE)
    
    #window1.connect("destroy", close_window, self)
    #window1.GTKPY_MAIN = self
    
    window1.add(x.widget)
    window1.show()
    return window1

