2008-08-21 23:19:18 +00:00
#!/usr/bin/python
2008-11-11 11:21:18 +00:00
from terminatorlib . config import dbg , err , Defaults , TerminatorConfValuestoreRC
2008-11-17 00:37:50 +00:00
from terminatorlib . keybindings import TerminatorKeybindings , Modifier
2008-08-21 23:19:18 +00:00
from terminatorlib . version import APP_NAME , APP_VERSION
2008-11-17 00:37:50 +00:00
import gtk , gobject
2008-08-21 23:19:18 +00:00
class ProfileEditor :
2008-10-28 00:29:54 +00:00
# lists of which settings to put in which tabs
appearance = [ ' titlebars ' , ' titletips ' , ' allow_bold ' , ' silent_bell ' , ' force_no_bell ' , ' background_darkness ' , ' background_type ' , ' background_image ' , ' cursor_blink ' , ' font ' , ' scrollbar_position ' , ' scroll_background ' , ' use_system_font ' , ' use_theme_colors ' , ' enable_real_transparency ' ]
2008-09-07 18:43:03 +00:00
colours = [ ' foreground_color ' , ' background_color ' , ' palette ' ]
behaviour = [ ' backspace_binding ' , ' delete_binding ' , ' emulation ' , ' scroll_on_keystroke ' , ' scroll_on_output ' , ' scrollback_lines ' , ' focus ' , ' focus_on_close ' , ' exit_action ' , ' word_chars ' , ' mouse_autohide ' , ' use_custom_command ' , ' custom_command ' , ' http_proxy ' , ' encoding ' ]
2008-10-28 00:29:54 +00:00
globals = [ ' fullscreen ' , ' maximise ' , ' borderless ' , ' handle_size ' , ' cycle_term_tab ' , ' close_button_on_tab ' , ' tab_position ' , ' copy_on_selection ' , ' extreme_tabs ' , ' try_posix_regexp ' ]
# metadata about the settings
2008-09-06 00:40:42 +00:00
data = { ' titlebars ' : [ ' Show titlebars ' , ' This places a bar above each terminal which displays its title. ' ] ,
' titletips ' : [ ' Show title tooltips ' , ' This adds a tooltip to each terminal which contains its title ' ] ,
' allow_bold ' : [ ' Allow bold text ' , ' Controls whether or not the terminals will honour requests for bold text ' ] ,
2008-10-28 00:29:54 +00:00
' silent_bell ' : [ ' ' , ' When enabled, bell events will generate a flash. When disabled, they will generate a beep ' ] ,
' background_darkness ' : [ ' ' , ' Controls how much the background will be tinted ' ] ,
' scroll_background ' : [ ' ' , ' When enabled the background image will scroll with the text ' ] ,
' force_no_bell ' : [ ' ' , ' Disable both the visual and audible bells ' ] ,
' tab_position ' : [ ' ' , ' Controls the placement of the tab bar ' ] ,
' use_theme_colors ' : [ ' ' , ' Take the foreground and background colours from the current GTK theme ' ] ,
' enable_real_transparency ' : [ ' ' , ' If you are running a composited desktop (e.g. compiz), enabling this option will enable " true " transpraency ' ] ,
' handle_size ' : [ ' ' , ' This controls the size of the border between terminals. Values 0 to 5 are in pixels, while -1 means the value will be decided by your normal GTK theme. ' ] ,
2008-11-17 02:08:47 +00:00
' close_window ' : [ ' Quit Terminator ' , ' ' ] ,
' toggle_zoom ' : [ ' Toggle maximise terminal ' , ' ' ] ,
' scaled_zoom ' : [ ' Toggle zoomed terminal ' , ' ' ] ,
' prev_tab ' : [ ' Previous tab ' , ' ' ] ,
' split_vert ' : [ ' Split vertically ' , ' ' ] ,
' split_horiz ' : [ ' Split horizontally ' , ' ' ] ,
' go_prev ' : [ ' Focus previous terminal ' , ' ' ] ,
' go_next ' : [ ' Focus next terminal ' , ' ' ] ,
' close_term ' : [ ' Close terminal ' , ' ' ] ,
' new_root_tab ' : [ ' New root tab ' , ' ' ] ,
' zoom_normal ' : [ ' Zoom reset ' , ' ' ] ,
2008-11-17 10:46:47 +00:00
' reset ' : [ ' Reset terminal state ' , ' ' ] ,
' reset_clear ' : [ ' Reset and clear terminal ' , ' ' ] ,
2009-01-25 18:33:22 +00:00
' hide_window ' : [ ' Toggle visibility of the window ' , ' ' ] ,
2008-09-06 00:40:42 +00:00
}
2008-08-21 23:19:18 +00:00
2008-11-03 22:55:55 +00:00
# dictionary for results after setting
widgets = { }
# combobox settings
scrollbar_position = [ ' left ' , ' right ' , ' disabled ' ]
2008-12-02 17:22:44 +00:00
backspace_del_binding = [ ' ascii-del ' , ' control-h ' , ' escape-sequence ' , ' delete-sequence ' ]
2008-11-12 02:44:57 +00:00
focus = [ ' click ' , ' sloppy ' , ' mouse ' ]
2008-11-03 22:55:55 +00:00
background_type = [ ' solid ' , ' image ' , ' transparent ' ]
tab_position = [ ' top ' , ' bottom ' , ' left ' , ' right ' ]
2008-11-19 13:46:37 +00:00
tab_position_gtk = { ' top ' : gtk . POS_TOP , ' bottom ' : gtk . POS_BOTTOM , ' left ' : gtk . POS_LEFT , ' right ' : gtk . POS_RIGHT }
2008-11-03 22:55:55 +00:00
def __init__ ( self , term ) :
self . term = term
2008-08-21 23:19:18 +00:00
self . window = gtk . Window ( )
self . notebook = gtk . Notebook ( )
2008-10-28 00:29:54 +00:00
self . box = gtk . VBox ( )
2008-11-03 22:55:55 +00:00
2008-11-01 00:50:34 +00:00
self . butbox = gtk . HButtonBox ( )
self . applybut = gtk . Button ( stock = gtk . STOCK_APPLY )
2008-11-03 22:55:55 +00:00
self . applybut . connect ( " clicked " , self . apply )
2008-11-01 00:50:34 +00:00
self . cancelbut = gtk . Button ( stock = gtk . STOCK_CANCEL )
2008-11-03 22:55:55 +00:00
self . cancelbut . connect ( " clicked " , self . cancel )
2008-10-28 00:29:54 +00:00
self . box . pack_start ( self . notebook , False , False )
2008-11-01 00:50:34 +00:00
self . box . pack_end ( self . butbox , False , False )
2008-11-03 22:55:55 +00:00
2008-11-01 00:50:34 +00:00
self . butbox . set_layout ( gtk . BUTTONBOX_END )
self . butbox . pack_start ( self . applybut , False , False )
self . butbox . pack_start ( self . cancelbut , False , False )
2008-10-28 00:29:54 +00:00
self . window . add ( self . box )
2008-08-21 23:19:18 +00:00
2008-09-07 18:43:03 +00:00
self . notebook . append_page ( self . auto_add ( gtk . Table ( ) , self . globals ) , gtk . Label ( " Global Settings " ) )
2008-11-17 00:37:50 +00:00
self . notebook . append_page ( self . prepare_keybindings ( ) , gtk . Label ( " Keybindings " ) )
2008-08-21 23:19:18 +00:00
self . notebook . append_page ( self . auto_add ( gtk . Table ( ) , self . appearance ) , gtk . Label ( " Appearance " ) )
2008-09-07 18:43:03 +00:00
self . notebook . append_page ( self . auto_add ( gtk . Table ( ) , self . colours ) , gtk . Label ( " Colours " ) )
2008-08-21 23:19:18 +00:00
self . notebook . append_page ( self . auto_add ( gtk . Table ( ) , self . behaviour ) , gtk . Label ( " Behaviour " ) )
2008-11-01 00:50:34 +00:00
def go ( self ) :
2008-08-21 23:19:18 +00:00
self . window . show_all ( )
2008-09-07 18:43:03 +00:00
def source_get_type ( self , key ) :
if Defaults . has_key ( key ) :
return Defaults [ key ] . __class__ . __name__
elif Defaults [ ' keybindings ' ] . has_key ( key ) :
return Defaults [ ' keybindings ' ] [ key ] . __class__ . __name__
else :
raise KeyError
def source_get_value ( self , key ) :
2008-11-11 11:21:18 +00:00
try :
return self . term . conf . __getattr__ ( key )
except AttributeError :
try :
2008-11-16 18:40:05 +00:00
return self . term . conf . keybindings [ key ]
2008-11-11 11:21:18 +00:00
except AttributeError :
pass
2008-09-07 18:43:03 +00:00
2008-11-17 02:08:47 +00:00
def source_get_keyname ( self , key ) :
if self . data . has_key ( key ) and self . data [ key ] [ 0 ] != ' ' :
label_text = self . data [ key ] [ 0 ]
else :
label_text = key . replace ( ' _ ' , ' ' ) . capitalize ( )
return label_text
2008-08-21 23:19:18 +00:00
def auto_add ( self , table , list ) :
row = 0
for key in list :
table . resize ( row + 1 , 2 )
2008-11-17 02:08:47 +00:00
label = gtk . Label ( self . source_get_keyname ( key ) )
2008-11-02 02:18:23 +00:00
wrapperbox = gtk . HBox ( )
wrapperbox . pack_start ( label , False , True )
2008-09-07 18:43:03 +00:00
type = self . source_get_type ( key )
value = self . source_get_value ( key )
2008-08-21 23:19:18 +00:00
widget = None
2008-08-24 06:39:49 +00:00
if key == ' font ' :
widget = gtk . FontButton ( value )
elif key == ' scrollback_lines ' :
# estimated byte size per line according to g-t:
# sizeof(void *) + sizeof(char *) + sizeof(int) + (80 * (sizeof(int32) + 4)
widget = gtk . SpinButton ( )
widget . set_digits ( 0 )
widget . set_increments ( 100 , 1000 )
widget . set_range ( 0 , 100000 )
widget . set_value ( value )
2008-09-04 00:26:49 +00:00
elif key == ' scrollbar_position ' :
2009-01-04 17:53:19 +00:00
if value == ' hidden ' :
value = ' disabled '
2008-09-04 00:26:49 +00:00
widget = gtk . combo_box_new_text ( )
2008-11-03 22:55:55 +00:00
for item in self . scrollbar_position :
widget . append_text ( item )
2008-11-12 01:45:52 +00:00
widget . set_active ( self . scrollbar_position . index ( value ) )
2008-09-07 19:10:06 +00:00
elif key == ' backspace_binding ' :
widget = gtk . combo_box_new_text ( )
2008-11-03 22:55:55 +00:00
for item in self . backspace_del_binding :
widget . append_text ( item )
2008-11-12 01:45:52 +00:00
widget . set_active ( self . backspace_del_binding . index ( value ) )
2008-09-07 19:10:06 +00:00
elif key == ' delete_binding ' :
widget = gtk . combo_box_new_text ( )
2008-11-03 22:55:55 +00:00
for item in self . backspace_del_binding :
widget . append_text ( item )
2008-11-12 01:45:52 +00:00
widget . set_active ( self . backspace_del_binding . index ( value ) )
2008-09-04 00:26:49 +00:00
elif key == ' focus ' :
widget = gtk . combo_box_new_text ( )
2008-11-03 22:55:55 +00:00
for item in self . focus :
widget . append_text ( item )
2008-11-12 01:45:52 +00:00
widget . set_active ( self . focus . index ( value ) )
2008-09-07 18:43:03 +00:00
elif key == ' background_type ' :
widget = gtk . combo_box_new_text ( )
2008-11-03 22:55:55 +00:00
for item in self . background_type :
widget . append_text ( item )
2008-11-12 01:45:52 +00:00
widget . set_active ( self . background_type . index ( value ) )
2008-09-07 18:43:03 +00:00
elif key == ' background_darkness ' :
widget = gtk . HScale ( )
widget . set_digits ( 1 )
widget . set_draw_value ( True )
widget . set_value_pos ( gtk . POS_LEFT )
widget . set_range ( 0 , 1 )
widget . set_value ( value )
elif key == ' handle_size ' :
widget = gtk . HScale ( )
widget . set_digits ( 0 )
widget . set_draw_value ( True )
widget . set_value_pos ( gtk . POS_LEFT )
widget . set_range ( - 1 , 5 )
widget . set_value ( value )
elif key == ' foreground_color ' :
widget = gtk . ColorButton ( gtk . gdk . color_parse ( value ) )
elif key == ' background_color ' :
widget = gtk . ColorButton ( gtk . gdk . color_parse ( value ) )
elif key == ' palette ' :
colours = value . split ( ' : ' )
numcolours = len ( colours )
widget = gtk . Table ( 2 , numcolours / 2 )
x = 0
y = 0
for thing in colours :
if x == numcolours / 2 :
y + = 1
x = 0
widget . attach ( gtk . ColorButton ( gtk . gdk . color_parse ( thing ) ) , x , x + 1 , y , y + 1 )
x + = 1
elif key == ' background_image ' :
widget = gtk . FileChooserButton ( ' Select a File ' )
filter = gtk . FileFilter ( )
filter . add_mime_type ( ' image/* ' )
widget . add_filter ( filter )
2008-11-12 11:58:01 +00:00
widget . set_local_only ( True )
2008-11-16 02:42:09 +00:00
if value :
widget . set_filename ( value )
2008-10-28 00:29:54 +00:00
elif key == ' tab_position ' :
widget = gtk . combo_box_new_text ( )
2008-11-03 22:55:55 +00:00
for item in self . tab_position :
widget . append_text ( item )
2008-11-12 01:45:52 +00:00
widget . set_active ( self . tab_position . index ( value ) )
2008-08-21 23:19:18 +00:00
else :
2008-08-24 06:39:49 +00:00
if type == " bool " :
widget = gtk . CheckButton ( )
widget . set_active ( value )
elif type in [ " str " , " int " , " float " ] :
widget = gtk . Entry ( )
widget . set_text ( str ( value ) )
elif type == " list " :
continue
else :
2008-11-11 11:21:18 +00:00
err ( " Unknown type: %s for key: %s " % ( type , key ) )
2008-08-24 06:39:49 +00:00
continue
2008-10-28 00:29:54 +00:00
if hasattr ( widget , ' set_tooltip_text ' ) and self . data . has_key ( key ) :
widget . set_tooltip_text ( self . data [ key ] [ 1 ] )
2008-11-03 22:55:55 +00:00
widget . set_name ( key )
self . widgets [ key ] = widget
2008-11-02 02:18:23 +00:00
table . attach ( wrapperbox , 0 , 1 , row , row + 1 , gtk . EXPAND | gtk . FILL , gtk . FILL )
2008-11-02 02:06:35 +00:00
table . attach ( widget , 1 , 2 , row , row + 1 , gtk . EXPAND | gtk . FILL , gtk . FILL )
2008-08-21 23:19:18 +00:00
row + = 1
return ( table )
2008-11-03 22:55:55 +00:00
def apply ( self , data ) :
2008-11-11 11:21:18 +00:00
values = { }
2008-11-03 22:55:55 +00:00
for page in [ self . appearance , self . behaviour , self . globals , self . colours ] :
for property in page :
widget = self . widgets [ property ]
2008-11-12 01:45:52 +00:00
if isinstance ( widget , gtk . SpinButton ) :
value = widget . get_value ( )
elif isinstance ( widget , gtk . Entry ) :
2008-11-03 22:55:55 +00:00
value = widget . get_text ( )
elif isinstance ( widget , gtk . CheckButton ) :
value = widget . get_active ( )
elif isinstance ( widget , gtk . ComboBox ) :
if widget . name == ' scrollbar_position ' :
bucket = self . scrollbar_position
elif widget . name == ' backspace_binding ' or widget . name == ' delete_binding ' :
bucket = self . backspace_del_binding
elif widget . name == ' focus ' :
bucket = self . focus
elif widget . name == ' background_type ' :
bucket = self . background_type
elif widget . name == ' tab_position ' :
bucket = self . tab_position
else :
2008-11-11 11:21:18 +00:00
err ( " Unknown bucket type for %s " % widget . name )
2008-11-03 22:55:55 +00:00
continue
value = bucket [ widget . get_active ( ) ]
elif isinstance ( widget , gtk . FontButton ) :
value = widget . get_font_name ( )
elif isinstance ( widget , gtk . HScale ) :
value = widget . get_value ( )
2008-11-11 11:21:18 +00:00
if widget . get_digits ( ) == 0 :
2008-11-03 23:14:29 +00:00
value = int ( value )
2008-11-03 22:55:55 +00:00
elif isinstance ( widget , gtk . ColorButton ) :
value = widget . get_color ( ) . to_string ( )
elif isinstance ( widget , gtk . FileChooserButton ) :
value = widget . get_filename ( )
elif widget . get_name ( ) == ' palette ' :
value = ' '
2008-11-11 11:21:18 +00:00
valuebits = [ ]
2008-11-03 22:55:55 +00:00
children = widget . get_children ( )
children . reverse ( )
for child in children :
2008-11-11 11:21:18 +00:00
valuebits . append ( child . get_color ( ) . to_string ( ) )
value = ' : ' . join ( valuebits )
2008-11-03 22:55:55 +00:00
else :
value = None
2008-11-12 11:36:18 +00:00
err ( " skipping unknown property: %s " % property )
2008-11-11 11:21:18 +00:00
values [ property ] = value
has_changed = False
2008-11-12 11:36:18 +00:00
changed = [ ]
2008-11-11 11:21:18 +00:00
for source in self . term . conf . sources :
if isinstance ( source , TerminatorConfValuestoreRC ) :
for property in values :
try :
2008-11-12 01:45:52 +00:00
if self . source_get_value ( property ) != values [ property ] :
2008-11-17 00:51:11 +00:00
dbg ( " %s changed from %s to %s " % ( property , self . source_get_value ( property ) , values [ property ] ) )
2008-11-11 11:21:18 +00:00
source . values [ property ] = values [ property ]
has_changed = True
2008-11-12 11:36:18 +00:00
changed . append ( property )
2008-11-11 11:21:18 +00:00
except KeyError :
pass
if has_changed :
2008-11-12 11:36:18 +00:00
for changer in changed :
if changer == " fullscreen " :
self . term . fullscreen_absolute ( values [ changer ] )
2008-11-16 02:42:09 +00:00
elif changer == " maximise " :
if values [ changer ] :
self . term . maximize ( )
else :
self . term . unmaximize ( )
elif changer == " borderless " :
self . term . window . set_decorated ( not values [ changer ] )
elif changer == " handle_size " :
2008-11-19 13:46:37 +00:00
self . term . set_handle_size ( values [ changer ] )
gtk . rc_reset_styles ( gtk . settings_get_default ( ) )
2008-11-16 02:42:09 +00:00
elif changer == " tab_position " :
2008-11-19 13:46:37 +00:00
notebook = self . term . window . get_child ( )
new_pos = self . tab_position_gtk [ values [ changer ] ]
angle = 0
if isinstance ( notebook , gtk . Notebook ) :
notebook . set_tab_pos ( new_pos )
2008-11-19 17:04:36 +00:00
for i in xrange ( 0 , notebook . get_n_pages ( ) ) :
notebook . get_tab_label ( notebook . get_nth_page ( i ) ) . update_angle ( )
2008-11-16 02:42:09 +00:00
pass
2008-11-19 17:04:36 +00:00
elif changer == " close_button_on_tab " :
notebook = self . term . window . get_child ( )
if isinstance ( notebook , gtk . Notebook ) :
for i in xrange ( 0 , notebook . get_n_pages ( ) ) :
notebook . get_tab_label ( notebook . get_nth_page ( i ) ) . update_closebut ( )
# FIXME: which others? cycle_term_tab, copy_on_selection, extreme_tabs, try_posix_regexp
2008-11-12 11:36:18 +00:00
2008-11-11 11:21:18 +00:00
self . term . reconfigure_vtes ( )
2008-11-12 11:58:01 +00:00
2008-11-17 02:08:47 +00:00
# Check for changed keybindings
2008-11-17 02:24:38 +00:00
changed_keybindings = [ ]
2008-11-17 02:08:47 +00:00
for row in self . liststore :
accel = gtk . accelerator_name ( row [ 2 ] , row [ 3 ] )
value = self . term . conf . keybindings [ row [ 0 ] ]
if isinstance ( value , tuple ) :
value = value [ 0 ]
2009-01-21 09:06:16 +00:00
keyval = 0
mask = 0
if value is not None :
( keyval , mask ) = self . tkbobj . _parsebinding ( value )
if ( row [ 2 ] , row [ 3 ] ) != ( keyval , mask ) :
2008-11-17 15:09:39 +00:00
changed_keybindings . append ( ( row [ 0 ] , accel ) )
dbg ( " %s changed from %s to %s " % ( row [ 0 ] , self . term . conf . keybindings [ row [ 0 ] ] , accel ) )
2008-11-17 02:24:38 +00:00
2008-11-17 15:09:39 +00:00
newbindings = self . term . conf . keybindings
for binding in changed_keybindings :
newbindings [ binding [ 0 ] ] = binding [ 1 ]
self . term . keybindings . configure ( newbindings )
2008-11-17 02:08:47 +00:00
2008-11-12 11:58:01 +00:00
# We're not actually cancelling, but since all it does is close the window, we might as well use it
self . cancel ( None )
2008-11-03 22:55:55 +00:00
def cancel ( self , data ) :
self . window . destroy ( )
self . term . options = None
del ( self )
2008-11-17 00:37:50 +00:00
def prepare_keybindings ( self ) :
2008-11-17 02:08:47 +00:00
self . liststore = gtk . ListStore ( gobject . TYPE_STRING , gobject . TYPE_STRING , gobject . TYPE_UINT , gobject . TYPE_UINT , gobject . TYPE_BOOLEAN )
self . liststore . set_sort_column_id ( 0 , gtk . SORT_ASCENDING )
self . tkbobj = TerminatorKeybindings ( )
2008-11-17 00:37:50 +00:00
keyval = None
mask = None
for binding in Defaults [ ' keybindings ' ] :
2008-11-17 02:08:47 +00:00
value = self . term . conf . keybindings [ binding ]
2009-01-21 09:06:16 +00:00
keyval = 0
mask = 0
if isinstance ( value , tuple ) :
value = value [ 0 ]
if value is not None :
( keyval , mask ) = self . tkbobj . _parsebinding ( value )
2008-11-17 02:08:47 +00:00
self . liststore . append ( [ binding , self . source_get_keyname ( binding ) , keyval , mask , True ] )
2008-11-17 00:51:11 +00:00
dbg ( " Appended row: %s , %s , %s " % ( binding , keyval , mask ) )
2008-11-17 00:37:50 +00:00
2008-11-17 02:08:47 +00:00
self . treeview = gtk . TreeView ( self . liststore )
2008-11-17 00:37:50 +00:00
cell = gtk . CellRendererText ( )
2008-11-17 02:08:47 +00:00
col = gtk . TreeViewColumn ( _ ( " Name " ) )
2008-11-17 00:37:50 +00:00
col . pack_start ( cell , True )
col . add_attribute ( cell , " text " , 0 )
2008-11-17 02:08:47 +00:00
self . treeview . append_column ( col )
cell = gtk . CellRendererText ( )
col = gtk . TreeViewColumn ( _ ( " Action " ) )
col . pack_start ( cell , True )
col . add_attribute ( cell , " text " , 1 )
self . treeview . append_column ( col )
2008-11-17 00:37:50 +00:00
cell = gtk . CellRendererAccel ( )
col = gtk . TreeViewColumn ( _ ( " Keyboard shortcut " ) )
col . pack_start ( cell , True )
2008-11-17 02:08:47 +00:00
col . set_attributes ( cell , accel_key = 2 , accel_mods = 3 , editable = 4 )
2008-11-17 00:37:50 +00:00
2008-11-17 02:24:38 +00:00
cell . connect ( ' accel-edited ' , self . edited )
2008-11-17 02:08:47 +00:00
self . treeview . append_column ( col )
2008-11-17 00:37:50 +00:00
2008-12-26 23:26:04 +00:00
scrollwin = gtk . ScrolledWindow ( )
scrollwin . set_policy ( gtk . POLICY_NEVER , gtk . POLICY_AUTOMATIC )
scrollwin . add ( self . treeview )
return ( scrollwin )
2008-11-17 00:37:50 +00:00
2008-11-17 02:24:38 +00:00
def edited ( self , obj , path , key , mods , code ) :
iter = self . liststore . get_iter_from_string ( path )
self . liststore . set ( iter , 2 , key , 3 , mods )