# PytkBackend.py
# 
# Copyright (c) 1999-2001 Philip Hunt
# parts Copyright (c) 2001 Ludger Humbert
# Released under the GNU General Public Licence
# 
# Python/Tkinter backend for Parrot
#
# This backend produces Python source code that uses the Tkinter
# API to produce the user interface

# Last altered: 14-Jun-2001
# History:
# 4-Sep-1999 PhilHunt: created
# 12-Feb-2000: added Html_textArea class
# 14-Jun-2001 PH: integration of LH's changes


from inrep import *
from backend import *

indentSize = 3
indent = ' ' * indentSize
in2 = indent + indent
slashComment = '#' + ('/'*69) + '\n'

#===========================================================
#####  mixin superclass of all Pytk_ classes
#===========================================================

sequenceNumber = 1


class Pytk_mixin:  
   def getVarName(self):
      # defaults to getting the object's id. This is
      # overridden in Pytk_window, which must return ``self'' instead  
      # if the component doesn't have an id, uses a default value 
      # instead; the default goes in (self.fakeId)      
      global sequenceNumber
      id = self.getId()
      
      if not id:
         if not hasattr(self, 'fakeId'):
            self.fakeId = 'par_' + self.type + `sequenceNumber`
            sequenceNumber = sequenceNumber + 1
         #print 'self.fakeId=' , self.fakeId
         return self.fakeId
      else:
         #print 'id=',id
         return self.getId()
         
         
   # goes up through the parts hierarchy until it returns an owner
   # whose (type) field is (ownerType). Then returns it.
   # if not found, returns None.
   def getOwnerOfType(self, ownerType):
      if self.type == ownerType: 
         return self
      elif self.parent == None: 
         return None
      else:
         return self.parent.getOwnerOfType(ownerType)

  
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# this classname is preceded by "_" to denote that makbacl 
# shouldn't attempt to create instances of it.

class _Pytk_component(Backend_component, Pytk_mixin): 
   pass 
        
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# this classname is preceded by "_" to denote that makbacl 
# shouldn't attempt to create instances of it.

class _Pytk_container(Backend_container, Pytk_mixin): 

   def getStartCode(self):
      return '(***start %s***)\n' % self.__class__.__name__
   
   def getCodeBetweenComponents(self):
      return '(***between %s***)\n' % self.__class__.__name__
    
   def getEndCode(self):
      return '(***end %s***)\n' % self.__class__.__name__

   # add a line of code (aLine) to (self.result)
   def addL(self, aLine):
      self.result = self.result + indent + indent + aLine + '\n'

#===========================================================
#####  Pytk backend  ####################################### 
#===========================================================

class Pytk_GLOBAL(Backend_GLOBAL, Pytk_mixin):

#--------------------------------------- 
   def produceCode(self):
      # list of class names for windows:
      self.windowClasses = [ ]
        
      return self.getCode()
      
#--------------------------------------- 
   def getStartCode(self):
      return """# %s
#
# This file was autogenerated by Parrot's PytkBackend module

from Tkinter import *
from Dialog import Dialog

""" % (self.outputFilename,)


#--------------------------------------- 
   def getCodeBetweenComponents(self): 
      return '\n' + slashComment + '\n'

#--------------------------------------- 
   def getEndCode(self):
      mainCode = slashComment
      if self.windowClasses:
         # there are window classes, so do 'main' code
         mainCode = slashComment + ("""
if __name__=='__main__':
   %s().mainloop()
""" % self.windowClasses[0]) + '\n' + slashComment

      result =  """%s
#(end %s)
""" % (mainCode, self.outputFilename)
      return result


#--------------------------------------- 
   def getBackendSignature(self): return 'Pytk'

#--------------------------------------- 
   # The Pytk backend produces files with a .py extension
   def fileExtension(self): return '.py'

#--------------------------------------- 
   # return list of container types understood by this backend:
   def getContainerTypes(self):
      return ('window', 'colLayout', 'rowLayout', 'table', 'tr', 'td',
         'menuBar', 'menu')

#--------------------------------------- 
   # return list of components which aren't containers
   def getNonContainerTypes(self):
      return ('menuItem', 'button', 'label', 'textField', 'checkBox',
         'radioButton')

#===========================================================
# containers
#===========================================================

class Pytk_window(_Pytk_container):

   def getAttrDoc(self):
      return {'id': 'the identifier of the HTML form',
         'text': 'the window title'}

#--------------------------------------- 

   def getStartCode(self):
      self.stubMethods = [ ]
      self.getGlobal().windowClasses.append(self.getExtVarName()) 
      #self.menuCode = '   #(no menubar)\n   def createMenuBar(self): pass\n\n'
      #self.guiCode = '   #(no GUI code)\n   def createGUI(self): pass\n\n'
      self.currentlyDone = 0
      result = '\n' + slashComment + """
class %s(Frame):

   def  __init__(self, parent=None):
      Frame.__init__(self, parent)
      self.pack()
      self.createMenuBar()
      self.createGUI()
      self.master.title("%s")
      self.master.iconname("%s")
 
""" %( self.getExtVarName(), self.getText(), self.getVarName())
      if self.components:
         # this window has some components
         if self.components[0].type == 'menuBar':
            result = result + indent + "def createMenuBar(self):\n"
         else:
            result = result + indent + "def createGUI(self):\n"        
      return result

#--------------------------------------- 

   def getCodeBetweenComponents(self): 
      result = ''
      oldComponent = self.components[self.currentlyDone]
      nextComponent = self.components[self.currentlyDone + 1]
      #print '---betw: %s %s---\n' %(nextComponent.type, oldComponent.type)
      if nextComponent.type != 'menuBar' and oldComponent.type == 'menuBar':
         result = indent + "def createGUI(self):\n"
      self.currentlyDone = self.currentlyDone + 1
      return result

#--------------------------------------- 

   def getEndCode(self):
      result = '\n#***** methods to be redefined\n' 
      for meth in self.stubMethods:
         result = result + ("""
   def %s(self):
      print '[%s %s]'      
""" % (meth, self.getId(), meth))
      result = result + '\n#***** end of methods to be redefined\n\n' 
      return result

   def getVarName(self):
      return 'self'
      
   def getExtVarName(self):
      return Pytk_mixin.getVarName(self)
      
   def connectComponent(self, sub): 
      return in2 + ("%s.pack(side=TOP, anchor=NW)\n"
         % sub.getVarName())
 
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_colLayout(_Pytk_container):
   def getAttrDoc(self):
      return {'text': "the colLayout's border name (to do)"}

   def getStartCode(self): 
      # columns are yellow
      result = "      %s = Frame(%s, relief=RIDGE, bd=4, bg='#8888ee')\n" \
         % ( self.getVarName(), self.parent.getVarName())
      
      return result 
      
   def getCodeBetweenComponents(self): 
      return '' 
      
   def getEndCode(self): 
      return self.parent.connectComponent(self)  

   def connectComponent(self, sub): 
      return in2 + ("%s.pack(side=TOP, anchor=NW)\n"
         % sub.getVarName())
 
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_rowLayout(_Pytk_container):
   def getAttrDoc(self):
      return {'text': "the rowLayout's border name (to do)"}

   def getStartCode(self): 
      # rows are yellow
      result = "      %s = Frame(%s, relief=RIDGE, bd=4, bg='#eeee88')\n" \
         % ( self.getVarName(), self.parent.getVarName())
      
      return result
      
   def getCodeBetweenComponents(self): 
      return '' 

   def getEndCode(self): 
      return self.parent.connectComponent(self)  
       
   def connectComponent(self, sub): 
      return in2 + ("%s.pack(side=LEFT, anchor=NW)\n"
         % sub.getVarName())
 
#===========================================================
# table containers
#===========================================================

class Pytk_table(_Pytk_container):
   def getAttrDoc(self):
      return {'text': 'the table title (to do)'}

   def getStartCode(self): 
      self.trRowNum = 0
      result = in2 + "%s = Frame(%s, relief=RIDGE, bd=4, bg='#ee8888')\n" \
         % ( self.getVarName(), self.parent.getVarName())
      return result
            
   def getCodeBetweenComponents(self): 
      self.trRowNum = self.trRowNum + 1
      return ''
      
   def getEndCode(self): 
      return self.parent.connectComponent(self)  
      

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_tr(_Pytk_container):
   def getAttrDoc(self):
      return { }
      
   def getStartCode(self): 
      self.tdColNum = 0
      return ''
      
   def getCodeBetweenComponents(self): 
      self.tdColNum = self.tdColNum + 1
      return ''
      
   def getEndCode(self): 
      return ''

 
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_td(_Pytk_container):
   def getAttrDoc(self):
      return {'rowspan': 
         'number of rows spanned by this table element (to do)',
         'colspan': 
         'number of columns spanned by this table element (to do)'}

   def getStartCode(self): 
      return in2 + '#getStartCode() ' + self.type + '\n'
      
   def getCodeBetweenComponents(self): 
      return in2 + '#*** between ' + self.type + '\n'
      
   def getEndCode(self): 
      return in2 + '#*** end ' + self.type + '\n'
      
   def connectComponent(self, sub): 
      rowNum = self.parent.parent.trRowNum
      colNum = self.parent.tdColNum
      return in2 + ("%s.grid(column=%d, row=%d, stick=N+W)\n"
         % (sub.getVarName(), colNum, rowNum))
 
   def getVarName(self):
      return self.parent.parent.getVarName()


#===========================================================
# menu classes
#===========================================================

class Pytk_menuBar(_Pytk_container):

   def getAttrDoc(self):
      return { }

   def getStartCode(self):
      self.result = ''
      self.addL('self.menubar = Frame(self, relief=RAISED, bd=2)')
      self.addL('self.menubar.pack(side=TOP, fill=X)')
      return self.result
      
   def getCodeBetweenComponents(self): 
      return ""
      
   def getEndCode(self): 
      return "\n"

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_menu(_Pytk_container): 

   def getAttrDoc(self):
      return {'text': 'the menu title'}

   def getStartCode(self): 
      return """
      #----- menu "%s"
      mbutton = Menubutton(self.menubar, text='%s', underline=0)
      mbutton.pack(side=LEFT)
      menu = Menu(mbutton, tearoff=N)
""" % (self.getText(), self.getText())

   def getCodeBetweenComponents(self): 
      return ""
      
   def getEndCode(self): 
      return "      mbutton['menu'] = menu\n"

   def getNumItems(self):
      return len(self.components)      

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_menuItem(_Pytk_component):
   def getAttrDoc(self):
      return {'text': 'the text in the menu item'}


   def getCode(self): 
      commandParameter = ""
      
      #>>>>> connect to _pressed function
      if self.getId():
         stubMethodName = self.getId() + '_pressed'
         commandParameter = ", command=self.%s" %stubMethodName
         self.getOwnerOfType('window').stubMethods.append(stubMethodName)

      result = "      menu.add_command(label='%s'%s)\n" % \
         (self.getText(), commandParameter)

      
      return result

   def getStartCode(self): 
      return ''
      
   def getEndCode(self): 
      return ''

#===========================================================
# non-container components
#===========================================================
 
class Pytk_button(_Pytk_component):
   def getAttrDoc(self):
      return {'id': 'the identifier of the HTML button',
         'text': "the button's text"}

   def getCode(self):
      result = in2 + ('%s = Button(%s, text="%s")\n' % (
         self.getVarName(), self.parent.getVarName(),
         self.getText()))
         
      #>>>>> connect to _pressed function
      if self.getId():
         stubMethodName = self.getId() + '_pressed'
         result = result + in2 + ('%s.config(command=self.%s)\n'
            % (self.getVarName(), stubMethodName ))
         self.getOwnerOfType('window').stubMethods.append(stubMethodName)
         
      #ask parent to pack it:
      result = result + self.parent.connectComponent(self)
      return result


#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_label(_Pytk_component):
   def getAttrDoc(self):
      return {'text': "the label's text"}

   def getCode(self):
      result = in2 + ('%s = Label(%s, text="%s")\n' % (
         self.getVarName(), self.parent.getVarName(),
         self.getText()))
      result = result + self.parent.connectComponent(self)
      return result

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_textField(_Pytk_component):
   def getAttrDoc(self):
      return {'id': 'the identifier of the HTML text field',
         'text': 'text that goes in the textfield at startup',
         'cols': 'number of columns in textfield'}

   def getCode(self):
      cols = '10' #default
      if self.attr.has_key('cols'):
         cols = '%s' % self.attr['cols'] 
      result = in2 + '%s = Text(%s, height=1, width=%s)\n' % (
         self.getVarName(), self.parent.getVarName(), cols) 
      if self.getText():
         result = result + in2 + ('%s.insert("1.0", "%s")\n'
            % (self.getVarName(), self.getText()))
      result = result + self.parent.connectComponent(self)
      return result
      
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_textArea(_Pytk_component):
   def getAttrDoc(self):
      return {'id': 'the identifier of the HTML text field',
         'text': 'text that goes in the textarea at startup',
         'xsize': 'number of columns in the textarea',
         'ysize': 'number of rows in the textarea'}

   def getCode(self):
      cols = '20' #default
      if self.attr.has_key('xsize'):
         cols = '%s' % self.attr['xsize'] 
      rows = '4' #default
      if self.attr.has_key('ysize'):
         rows = '%s' % self.attr['ysize'] 
      result = in2 + '%s = Text(%s, height=%s, width=%s)\n' % (
         self.getVarName(), self.parent.getVarName(), rows, cols) 
      if self.getText():
         result = result + in2 + ('%s.insert("1.0", "%s")\n'
            % (self.getVarName(), self.getText()))
      result = result + self.parent.connectComponent(self)
      return result

        

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_checkBox(_Pytk_component):
   def getAttrDoc(self):
      return {'id': 'the identifier of the HTML checkbox',
         'text': "the checkbox's text"}

   def getCode(self):
      result = in2 + ("%s = Checkbutton(%s, text='%s')\n" % (
         self.getVarName(), self.parent.getVarName(), self.getText())) 
      result = result + self.parent.connectComponent(self) 
      
      #>>>>> connect to _pressed function
      if self.getId():
         stubMethodName = self.getId() + '_toggled'
         result = result + in2 + ('%s.config(command=self.%s)\n'
            % (self.getVarName(), stubMethodName ))
         self.getOwnerOfType('window').stubMethods.append(stubMethodName)
    
      return result

  
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Pytk_radioButton(_Pytk_component):
   def getAttrDoc(self):
      return {'label': 'the label for all this radio buttons',
         'id': 'the identifier of the HTML radio button',
         'text': "the radio button's text"}

   def getCode(self):
      result = in2 + ("%s = Radiobutton(%s, text='%s', value='%s')\n" % (
         self.getVarName(), self.parent.getVarName(), self.getText(), self.getText())) 
      result = result + self.parent.connectComponent(self)
            
      #>>>>> connect to _pressed function
      if self.getId():
         stubMethodName = self.getId() + '_toggled'
         result = result + in2 + ('%s.config(command=self.%s)\n'
            % (self.getVarName(), stubMethodName ))
         self.getOwnerOfType('window').stubMethods.append(stubMethodName)
    
      return result

  

#===========================================================

#end 




