Package pyplusplus :: Package gui :: Module ui

# Source Code for Module pyplusplus.gui.ui

      1  #! /usr/bin/python
      2  # Copyright 2004-2008 Roman Yakovenko.
      3  # Distributed under the Boost Software License, Version 1.0. (See
      4  # accompanying file LICENSE_1_0.txt or copy at
      5  # http://www.boost.org/LICENSE_1_0.txt)
      6
      7  """this module implements GUI.
      8
      9  TODO: It could be nice, if GUI will save the user settings beetwen runs.
     10  """
     11
     12  import os
     13  import sys
     14  import time
     15  import Tkinter
     16  import tkFileDialog
     17  import tkSimpleDialog
     18
     19  from pygccxml import parser
     20  from pyplusplus import module_builder
     21
     22  import wizard
     23
     24
     25 -class gui_config_t:
     26
     27      @staticmethod
     28 -    def config_file():
     29          config_path = os.getenv( 'HOME', os.path.abspath( os.getcwd() ) )
     30          return os.path.join( os.path.abspath( config_path ), ".pyplusplus" )
     31
     32      @staticmethod
     33 -    def read_header_name():
     34          config_path = gui_config_t.config_file()
     35          if os.path.exists(config_path):
     36              return open(config_path).read()
     37          else:
     38              return ''
     39
     40      @staticmethod
     41 -    def save_header_name( header_file ):
     42          config_path = gui_config_t.config_file()
     43          open(config_path, "w").write(header_file)
     44
     45  #TODO: add configuration file and ability to start\run it.
     46
     47 -class custom_frame_t(Tkinter.Frame):
     48 -    def __init__(self, parent, sticky=Tkinter.NSEW ):
     49          Tkinter.Frame.__init__( self, parent )
     50          self.grid( sticky=sticky)
     51
     52          self.rowconfigure( 1, weight=1 )
     53          self.columnconfigure( 0, weight=1 )
     54
     55
     56 -class parser_configuration_ui_t(custom_frame_t):
     57 -    def __init__(self, parent ):
     58          custom_frame_t.__init__( self, parent, sticky=Tkinter.NW )
     59
     60          temp = Tkinter.Label( self, text="Parser configuration", justify=Tkinter.LEFT)
     61          temp.grid( row=0, sticky=Tkinter.NW + Tkinter.E, columnspan=3)
     62          temp.configure( relief=Tkinter.GROOVE, borderwidth=1 )
     63
     64          temp = Tkinter.Label( self, text="GCC_XML location:")
     65          temp.grid( row=1, sticky=Tkinter.NW)
     66
     67          self._gccxml_location = Tkinter.Entry( self, width=35 )
     68          self._gccxml_location.grid(row=2, column=0, columnspan=2)
     69
     70          temp = Tkinter.Button( self, text="...", command=self._select_gccxml_executable )
     71          temp.grid( row=2, column=2)
     72
     73          temp = Tkinter.Label( self, text="Include paths:", justify=Tkinter.LEFT)
     74          temp.grid( row=3, sticky=Tkinter.NW)
     75
     76          self._include_paths = Tkinter.Listbox( self, height=9, width=35 )
     77          vscrollbar = Tkinter.Scrollbar( self, orient=Tkinter.VERTICAL)
     78          hscrollbar = Tkinter.Scrollbar( self, orient=Tkinter.HORIZONTAL)
     79
     80          self._include_paths.config( yscrollcommand=vscrollbar.set
     81                                       , xscrollcommand=hscrollbar.set )
     82          vscrollbar.config( command=self._include_paths.yview )
     83          hscrollbar.config( command=self._include_paths.xview )
     84
     85          self._include_paths.grid( row=4, column=0, columnspan=2, sticky=Tkinter.NW )
     86          vscrollbar.grid( row=4, column=2, sticky=Tkinter.NS + Tkinter.W )
     87          hscrollbar.grid( row=5, column=0, columnspan=2, sticky=Tkinter.EW )
     88
     89          temp = Tkinter.Button( self, text="add", command=self._add_include_path )
     90          temp.grid( row=6, column=0, sticky=Tkinter.NW + Tkinter.E)
     91          temp = Tkinter.Button( self, text="remove", command=self._remove_include_path )
     92          temp.grid( row=6, column=1, columnspan=2, sticky=Tkinter.NE + Tkinter.W)
     93
     94          temp = Tkinter.Label( self, text="Defines:", justify=Tkinter.LEFT)
     95          temp.grid( row=7, sticky=Tkinter.NW)
     96
     97          self._defines = Tkinter.Listbox( self, height=9, width=35 )
     98          vscrollbar = Tkinter.Scrollbar( self, orient=Tkinter.VERTICAL)
     99          hscrollbar = Tkinter.Scrollbar( self, orient=Tkinter.HORIZONTAL)
    100
    101          self._defines.config( yscrollcommand=vscrollbar.set
    102                                , xscrollcommand=hscrollbar.set )
    103          vscrollbar.config( command=self._defines.yview )
    104          hscrollbar.config( command=self._defines.xview )
    105
    106          self._defines.grid( row=8, column=0, columnspan=2, sticky=Tkinter.NW )
    107          vscrollbar.grid( row=8, column=2, sticky=Tkinter.NS + Tkinter.W )
    108          hscrollbar.grid( row=9, column=0, columnspan=2, sticky=Tkinter.EW )
    109
    110          temp = Tkinter.Button( self, text="add", command=self._add_define )
    111          temp.grid( row=10, column=0, sticky=Tkinter.NW + Tkinter.E)
    112          temp = Tkinter.Button( self, text="remove", command=self._remove_define )
    113          temp.grid( row=10, column=1, columnspan=2, sticky=Tkinter.NE + Tkinter.W)
    114
    115          map( lambda i:  self.rowconfigure( i, weight=1 ), range(11) )
    116
    117          this_module_dir_path = os.path.abspath ( os.path.dirname( sys.modules[__name__].__file__) )
    118          this_module_dir_path = this_module_dir_path.replace( '\\', '/' )
    119          this_module_dir_path = this_module_dir_path.lower()
    120          if this_module_dir_path.endswith( '/sources/pyplusplus_dev/pyplusplus/gui' ):
    121              gccxml_09_path = os.path.join( this_module_dir_path, '..', '..', '..', 'gccxml_bin', 'v09', sys.platform, 'bin' )
    122              self._gccxml_location.insert( 0, gccxml_09_path )
    123
    124 -    def _select_gccxml_executable( self ):
    125          file_name = tkFileDialog.askopenfilename()
    126          if not file_name:
    127              return
    128          self._gccxml_location.delete( 0, Tkinter.END )
    129          self._gccxml_location.insert( 0, file_name )
    130
    131 -    def _add_include_path( self ):
    132          directory = tkFileDialog.askdirectory()
    133          if directory:
    134              self._include_paths.insert( Tkinter.END, directory )
    135
    136 -    def _remove_include_path(self):
    137          selected = list( self._include_paths.curselection() )
    138          selected = map( int, selected )
    139          selected.sort()
    140          selected.reverse()
    141          map( self._include_paths.delete, selected )
    142
    143 -    def _add_define( self ):
    144          symbol = tkSimpleDialog.askstring(title='Py++ - code generator demo'
    145                                               , prompt="Define symbol ( example 'max(a,b)=a<b?b:a' ):")
    146          if symbol:
    147              self._defines.insert( Tkinter.END, symbol )
    148
    149 -    def _remove_define(self):
    150          selected = list( self._defines.curselection() )
    151          selected = map( int, selected )
    152          selected.sort()
    153          selected.reverse()
    154          map( self._defines.delete, selected )
    155
    156 -    def parser_configuration(self):
    157          return parser.config_t( gccxml_path=self._gccxml_location.get()
    158                                  , include_paths=list(self._include_paths.get( 0, Tkinter.END ) )
    159                                  , define_symbols=list(self._defines.get( 0, Tkinter.END ) ) )
    160
    161 -class header_file_ui_t(custom_frame_t):
    162 -    def __init__(self, parent ):
    163          custom_frame_t.__init__( self, parent, sticky=Tkinter.NW )
    164
    165          temp = Tkinter.Label( self, text="Header file:", justify=Tkinter.LEFT)
    166          temp.grid( row=0, sticky=Tkinter.NW + Tkinter.E, columnspan=3)
    167          temp.configure( relief=Tkinter.GROOVE, borderwidth=1 )
    168
    169          self._header_file = Tkinter.Entry( self, width=35 )
    170          self._header_file.grid(row=1, column=0, sticky=Tkinter.NW + Tkinter.E)
    171
    172          initial_header = gui_config_t.read_header_name()
    173          if initial_header:
    174              self._header_file.delete( 0, Tkinter.END )
    175              self._header_file.insert( 0, initial_header )
    176
    177          temp = Tkinter.Button( self, text="...", command=self._select_header_file )
    178          temp.grid( row=1, column=2)
    179
    180          map( lambda i:  self.rowconfigure( i, weight=1 ), range(2) )
    181
    182
    183 -    def _select_header_file( self ):
    184          file_name = tkFileDialog.askopenfilename()
    185          if not file_name:
    186              return
    187          self._header_file.delete( 0, Tkinter.END )
    188          self._header_file.insert( 0, file_name )
    189
    190 -    def header_file(self):
    191          hf = self._header_file.get()
    192          if not os.path.isabs( hf ):
    193              hf = os.path.abspath( hf )
    194          return hf
    195
    196 -class actions_ui_t(custom_frame_t):
    197 -    def __init__(self
    198                   , parent
    199                   , on_generate_code
    200                   , on_generate_pyplusplus
    201                   , on_create_gccxml):
    202          custom_frame_t.__init__( self, parent, sticky=Tkinter.NW )
    203
    204          temp = Tkinter.Button( self
    205                                 , width=37
    206                                 , text="generate code"
    207                                 , command=on_generate_code )
    208          temp.grid( row=0, columnspan=3, sticky=Tkinter.NW + Tkinter.E )
    209
    210          temp = Tkinter.Button( self
    211                                 , text="generate Py++ code"
    212                                 , command=on_generate_pyplusplus )
    213          temp.grid( row=1, sticky=Tkinter.NW + Tkinter.E)
    214
    215          temp = Tkinter.Button( self
    216                                 , text="create XML"
    217                                 , command=on_create_gccxml )
    218          temp.grid( row=2, sticky=Tkinter.NW + Tkinter.E)
    219
    220          map( lambda i:  self.rowconfigure( i, weight=1 ), range(3) )
    221          #self.columnconfigure( 0, weight=1 )
    222
    223 -class generated_code_ui_t(custom_frame_t):
    224 -    def __init__(self, parent):
    225          custom_frame_t.__init__( self, parent )
    226
    227          temp = Tkinter.Label( self, text="Generated code")
    228          temp.grid( row=0, sticky=Tkinter.NW + Tkinter.E, columnspan=2)
    229          temp.configure( relief=Tkinter.GROOVE, borderwidth=1 )
    230
    231          self._generated_code = Tkinter.Text( self, width=80, height=40)
    232          vscrollbar = Tkinter.Scrollbar( self, orient=Tkinter.VERTICAL)
    233          hscrollbar = Tkinter.Scrollbar( self, orient=Tkinter.HORIZONTAL)
    234
    235          self._generated_code.config( yscrollcommand=vscrollbar.set
    236                                       , xscrollcommand=hscrollbar.set
    237                                       , wrap=Tkinter.NONE )
    238          vscrollbar.config( command=self._generated_code.yview )
    239          hscrollbar.config( command=self._generated_code.xview )
    240
    241          self._generated_code.grid( row=1, column=0, sticky=Tkinter.NSEW)
    242          vscrollbar.grid( row=1, column=1, sticky=Tkinter.N + Tkinter.S)
    243          hscrollbar.grid( row=2, column=0, sticky=Tkinter.W + Tkinter.E)
    244
    245          self.rowconfigure( 1, weight=1 )
    246          self.columnconfigure( 0, weight=1 )
    247
    248 -    def set_generated_code(self, code ):
    249          self._generated_code.delete( 1.0, Tkinter.END )
    250          self._generated_code.insert( Tkinter.END, code )
    251
    252 -class statistics_t(custom_frame_t):
    253 -    def __init__(self, parent):
    254          custom_frame_t.__init__( self, parent )
    255
    256          temp = Tkinter.Label( self, text="Statistics", justify=Tkinter.LEFT)
    257          temp.grid( row=0, sticky=Tkinter.NW + Tkinter.E, columnspan=3)
    258          temp.configure( relief=Tkinter.GROOVE, borderwidth=1 )
    259
    260          temp = Tkinter.Label( self, text="Parse time:")
    261          temp.grid( row=1, column=0, sticky=Tkinter.NW)
    262
    263          self._parse_time = Tkinter.Label( self, text="0 seconds")
    264          self._parse_time.grid( row=1, column=1, sticky=Tkinter.NW)
    265
    266          temp = Tkinter.Label( self, text="Code generation time:")
    267          temp.grid( row=2, column=0, sticky=Tkinter.NW)
    268
    269          self._code_generation_time = Tkinter.Label( self, text="0 seconds")
    270          self._code_generation_time.grid( row=2, column=1, sticky=Tkinter.NW)
    271
    272 -    def set_parse_time(self, time ):
    273          self._parse_time.config( text='%0.2f seconds' % time )
    274
    275 -    def set_code_generation_time(self, time ):
    276          self._code_generation_time.config( text='%0.2f seconds' % time )
    277
    278 -class main_widget_ui_t(custom_frame_t):
    279 -    def __init__(self, parent=None ):
    280          custom_frame_t.__init__( self, parent )
    281
    282          top = self.winfo_toplevel()
    283          top.rowconfigure( 0, weight=1 )
    284          top.columnconfigure( 0, weight=1 )
    285
    286          self.master.title('Py++ - code generator demo')
    287
    288          self._header_file_configurator = header_file_ui_t( self )
    289          self._header_file_configurator.grid( row=0, column=0, sticky=Tkinter.NW, padx=2, pady=2)
    290
    291          self._parser_configurator = parser_configuration_ui_t( self )
    292          self._parser_configurator.grid( row=1, column=0, sticky=Tkinter.NW, padx=2)
    293
    294          self._actions_ui = actions_ui_t( self
    295                                           , on_generate_code=lambda:self._generate_code()
    296                                           , on_generate_pyplusplus=lambda: self._generate_pyplusplus()
    297                                           , on_create_gccxml=lambda:self._create_xml())
    298
    299          self._actions_ui.grid( row=3, column=0, rowspan=4, sticky=Tkinter.SE +Tkinter.W, padx=2 )
    300
    301          self._generated_code = generated_code_ui_t(self)
    302          self._generated_code.grid( row=0, column=1, rowspan=5, sticky=Tkinter.NSEW, pady=2)
    303
    304          self._statistics = statistics_t( self )
    305          self._statistics.grid( row=6, column=1, sticky=Tkinter.EW + Tkinter.S  )
    306
    307          self.rowconfigure( 0, weight=1 )
    308          self.rowconfigure( 1, weight=1 )
    309          self.rowconfigure( 2, weight=1 )
    310          self.rowconfigure( 3, weight=1 )
    311          self.rowconfigure( 4, weight=1 )
    312          self.rowconfigure( 5, weight=0 )
    313          self.rowconfigure( 6, weight=0 )
    314
    315          self.columnconfigure( 0, weight=0 )
    316          self.columnconfigure( 1, weight=1 )
    317
    318 -    def _generate_pyplusplus(self):
    319          config = self._parser_configurator.parser_configuration()
    320          header_file = self._header_file_configurator.header_file()
    321          config.include_paths.append( os.path.split( header_file )[0] )
    322          config.working_directory = os.path.split( header_file )[0]
    323          w = wizard.wizard_t( config, header_file )
    324          self._generated_code.set_generated_code( w.create_code() )
    325
    326 -    def _create_xml( self ):
    327          try:
    328              start_time = time.clock()
    329              config = self._parser_configurator.parser_configuration()
    330              header_file = self._header_file_configurator.header_file()
    331              config.include_paths.append( os.path.split( header_file )[0] )
    332              config.working_directory = os.path.split( header_file )[0]
    333              reader = parser.source_reader_t( config=config )
    334              xml_file = reader.create_xml_file( header_file )
    335              parsed_time = time.clock() - start_time
    336              xml_file_obj = file( xml_file )
    337              self._generated_code.set_generated_code( xml_file_obj.read() )
    338              xml_file_obj.close()
    339              os.remove( xml_file )
    340              self._statistics.set_parse_time( parsed_time )
    341              self._statistics.set_code_generation_time( 0 )
    342          except Exception, error:
    343              user_msg = [ 'Error occured during code generation process!' ]
    344              user_msg.append( 'Error:' )
    345              user_msg.append( str( error ) )
    346              self._generated_code.set_generated_code( '\n'.join( user_msg ) )
    347
    348 -    def _generate_code(self):
    349          global save_header_name
    350
    351          try:
    352              config = self._parser_configurator.parser_configuration()
    353              header_file = self._header_file_configurator.header_file()
    354              if not header_file or not os.path.isfile( header_file ):
    355                  raise RuntimeError( 'Header file "%s" does not exist or should be valid file name.' % header_file )
    356              gui_config_t.save_header_name( header_file )
    357              config.include_paths.append( os.path.split( header_file )[0] )
    358
    359              start_time = time.clock()
    360              mb = module_builder.module_builder_t(
    361                      [ header_file ]
    362                      , gccxml_path=config.gccxml_path
    363                      , working_directory=os.path.split( header_file )[0]
    364                      , include_paths=config.include_paths
    365                      , define_symbols=config.define_symbols )
    366
    367              parsed_time = time.clock() - start_time
    368
    369              mb.build_code_creator( "pyplusplus" )
    370              mb.code_creator.user_defined_directories.extend( config.include_paths )
    371              code = mb.code_creator.create()
    372              code = code.replace( '\n\r', '\n' )
    373              code = code.replace( '\r\n', '\n' )
    374              code_generated_time = time.clock() - start_time - parsed_time
    375              self._generated_code.set_generated_code( code )
    376              self._statistics.set_parse_time( parsed_time )
    377              self._statistics.set_code_generation_time( code_generated_time )
    378          except Exception, error:
    379              user_msg = [ 'Error occured during code generation process!' ]
    380              user_msg.append( 'Error:' )
    381              user_msg.append( str( error ) )
    382              self._generated_code.set_generated_code( '\n'.join( user_msg ) )
    383
    384 -    def _copy_to_clipboard(self):
    385          pass
    386
    387 -def show_demo():
    388      root = Tkinter.Tk()
    389      mw = main_widget_ui_t(root)
    390      root.geometry("%dx%d%+d%+d" % (1024, 768, 0, 0)) # (width,height, x, y)
    391      mw.mainloop()
    392
    393  if __name__ == "__main__":
    394      show_demo()
    395