home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / gnome-games-data / glchess / gtkui / network.py < prev   
Encoding:
Python Source  |  2009-04-14  |  24.6 KB  |  644 lines

  1. # -*- coding: utf-8 -*-
  2. import gettext
  3.  
  4. import gobject
  5. import gtk
  6. import pango
  7.  
  8. import gtkui
  9. import glchess.ui
  10.  
  11. _ = gettext.gettext
  12.  
  13. class GtkNetworkAddDialog:
  14.     def __init__(self, networkDialog, parent):
  15.         self.__networkDialog = networkDialog
  16.  
  17.         # Load the UI
  18.         self.__gui = gtkui.loadGladeFile('network_game.glade', 'add_account_dialog')
  19.         self.__gui.signal_autoconnect(self)
  20.         
  21.         self.__gui.get_widget('add_account_dialog').set_transient_for(parent)
  22.         
  23.         # FIXME: Hard-coded servers       
  24.         # name, host, port
  25.         self.serverModel = gtk.ListStore(str, str, int)
  26.         # Translators: Add Network Profile Dialog: Connect to the GGZ Gaming Zone server (the default)
  27.         self.serverModel.set(self.serverModel.append(), 0, _("GGZ Gaming Zone"), 1, "gnome.ggzgamingzone.org", 2, 5688)
  28.         # Translators: Add Network Profile Dialog: Use a custom server
  29.         self.serverModel.set(self.serverModel.append(), 0, _("Custom"), 1, "", 2, 5688)
  30.         
  31.         widget = self.__gui.get_widget('server_combo')
  32.         widget.set_model(self.serverModel)
  33.         cell = gtk.CellRendererText()
  34.         widget.pack_start(cell, False)
  35.         widget.add_attribute(cell, 'text', 0)
  36.         widget.set_model(self.serverModel)
  37.         widget.set_active(0)
  38.  
  39.     def setVisible(self, isVisible):
  40.         widget = self.__gui.get_widget('add_account_dialog')
  41.         if isVisible:
  42.             widget.present()
  43.         else:
  44.             widget.hide()
  45.             self.clear()
  46.             
  47.     def clear(self):
  48.         self.__gui.get_widget('server_combo').set_active(0)
  49.         self.__gui.get_widget('username_entry').set_text('')        
  50.             
  51.     def _on_server_changed(self, widget):
  52.         widget = self.__gui.get_widget('server_combo')
  53.         model = widget.get_model()
  54.         iter = widget.get_active_iter()
  55.         (host,) = model.get(iter, 1)
  56.         (port,) = model.get(iter, 2)
  57.         self.__gui.get_widget('host_entry').set_text(host)
  58.         self.__gui.get_widget('port_spin').set_value(port)
  59.         table = self.__gui.get_widget('custom_server_table')
  60.         if host == '':
  61.             table.show()
  62.         else:
  63.             table.hide()
  64.             
  65.     def have_data(self):
  66.         username = self.__gui.get_widget('username_entry').get_text()
  67.         host = self.__gui.get_widget('host_entry').get_text()
  68.         return username != '' and host != ''
  69.  
  70.     def _on_input_changed(self, widget):
  71.         self.__gui.get_widget('add_button').set_sensitive(self.have_data())
  72.  
  73.     def _on_username_activate(self, widget):
  74.         if self.have_data():
  75.             self._on_response(None, gtk.RESPONSE_OK)
  76.  
  77.     def _on_response(self, widget, response_id):
  78.         username = self.__gui.get_widget('username_entry').get_text()
  79.         host = self.__gui.get_widget('host_entry').get_text()
  80.         port = self.__gui.get_widget('port_spin').get_value_as_int()
  81.         name = '%s@%s' % (username, host) # FIXME
  82.         
  83.         if response_id == gtk.RESPONSE_OK:
  84.             profile = self.__networkDialog.feedback.addProfile((name, username, host, port))
  85.             self.__networkDialog.addProfile(profile, profile.name, useNow = True)
  86.         
  87.         self.__gui.get_widget('add_account_dialog').hide()
  88.         self.clear()
  89.             
  90.     def _on_delete(self, widget, event):
  91.         # Hide; don't delete this window
  92.         return True
  93.  
  94. class GtkNetworkGameDialog(glchess.ui.NetworkController):
  95.     """
  96.     """
  97.     def __init__(self, mainUI, feedback):
  98.         """Constructor for a new game dialog.
  99.         
  100.         'mainUI' is the main UI.
  101.         'feedback' is the object to feedback events with.
  102.         """
  103.         self.__mainUI = mainUI
  104.         self.feedback = feedback
  105.  
  106.         # Load the UI
  107.         self.__gui = gtkui.loadGladeFile('network_game.glade', 'network_game_dialog')
  108.         self.__gui.signal_autoconnect(self)
  109.         
  110.         # Selected profile
  111.         self.__profile = None
  112.         
  113.         self.profileModel = gtk.ListStore(gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, str)
  114.         # Translators: Server Combo Box: Not connected to a server
  115.         self.profileModel.set(self.profileModel.append(), 0, None, 1, self._set_profile, 2, _('Disconnected'))
  116.         self.profileModelSuffixCount = 0
  117.         self.profileModel.set(self.profileModel.append(), 1, None)
  118.         self.profileModelSuffixCount += 1
  119.         # Translators: Server Combo Box: Add new profile
  120.         self.profileModel.set(self.profileModel.append(), 0, None, 1, self._new_profile, 2, _('New profile...'))
  121.         self.profileModelSuffixCount += 1
  122.  
  123.         widget = self.__gui.get_widget('server_combo')
  124.         widget.set_model(self.profileModel)
  125.         widget.set_active(0)
  126.         widget.set_row_separator_func(self._is_profile_model_separator)
  127.         cell = gtk.CellRendererText()
  128.         widget.pack_start(cell, False)
  129.         widget.add_attribute(cell, 'text', 2)
  130.  
  131.         # room object, index, name, num players, description, font weight, font style, icon_name
  132.         self.roomModel = gtk.TreeStore(gobject.TYPE_PYOBJECT, int, str, str, str, int, int, str)
  133.         self.firstNonChessIter = None
  134.         self.roomIters = {}
  135.         view = self.__gui.get_widget('room_list')
  136.         view.set_model(self.roomModel)
  137.         cell = gtk.CellRendererText()
  138.         column = gtk.TreeViewColumn('', cell)
  139.         column.add_attribute(cell, 'text', 3)
  140.         view.append_column(column)
  141.         cell = gtk.CellRendererPixbuf()
  142.         column = gtk.TreeViewColumn('', cell)
  143.         column.add_attribute(cell, 'icon-name', 7)
  144.         view.append_column(column)
  145.         cell = gtk.CellRendererText()
  146.         column = gtk.TreeViewColumn('', cell)
  147.         column.add_attribute(cell, 'text', 2)
  148.         column.add_attribute(cell, 'weight', 5)
  149.         column.add_attribute(cell, 'style', 6)
  150.         view.append_column(column)
  151.         cell = gtk.CellRendererText()
  152.         column = gtk.TreeViewColumn('', cell)
  153.         column.add_attribute(cell, 'text', 4)
  154.         #view.append_column(column)
  155.         view.connect('row-activated', self._on_room_changed)
  156.  
  157.         # player, name, icon
  158.         self.playerModel = gtk.ListStore(gobject.TYPE_PYOBJECT, str, str)
  159.         view = self.__gui.get_widget('player_list')
  160.         view.set_model(self.playerModel)
  161.         cell = gtk.CellRendererPixbuf()
  162.         column = gtk.TreeViewColumn('', cell)
  163.         column.add_attribute(cell, 'icon-name', 2)
  164.         view.append_column(column)
  165.         cell = gtk.CellRendererText()
  166.         column = gtk.TreeViewColumn('', cell)
  167.         column.add_attribute(cell, 'text', 1)
  168.         view.append_column(column)
  169.  
  170.         # table, number, seats, description, seat model, can connect
  171.         self.tableModel = gtk.ListStore(gobject.TYPE_PYOBJECT, str, str, str, gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN)
  172.         self.tableIters = {}
  173.         
  174.         view = self.__gui.get_widget('table_list')
  175.         view.get_selection().connect('changed', self._on_table_selected)
  176.         view.set_model(self.tableModel)
  177.         
  178.         cell = gtk.CellRendererText()
  179.         # Translators: Available GGZ Tables: Table name column title
  180.         column = gtk.TreeViewColumn(_('Table'), cell)
  181.         column.add_attribute(cell, 'text', 1)
  182.         view.append_column(column)
  183.         cell = gtk.CellRendererText()
  184.         # Translators: Available GGZ Tables: Seat status column title
  185.         column = gtk.TreeViewColumn(_('Seats'), cell)
  186.         column.add_attribute(cell, 'text', 2)
  187.         view.append_column(column)
  188.         cell = gtk.CellRendererText()
  189.         # Translators: Available GGZ Tables: Table description column title        
  190.         column = gtk.TreeViewColumn(_('Description'), cell)
  191.         column.add_attribute(cell, 'text', 3)
  192.         view.append_column(column)
  193.  
  194.         view = self.__gui.get_widget('seat_list')
  195.         cell = gtk.CellRendererText()
  196.         # Translators: Current GGZ Table: Seat name column title
  197.         column = gtk.TreeViewColumn(_('Seat'), cell)
  198.         column.add_attribute(cell, 'text', 2)
  199.         view.append_column(column)
  200.         # Translators: Current GGZ Table: Player name column title        
  201.         column = gtk.TreeViewColumn(_('Player'), cell)
  202.         column.add_attribute(cell, 'text', 3)
  203.         column.add_attribute(cell, 'style', 4)
  204.         view.append_column(column)
  205.         
  206.         self.__loadThrobber()
  207.  
  208.         # Create styles for the buffer
  209.         buffer = self.__gui.get_widget('chat_textview').get_buffer()
  210.         buffer.create_tag('motd', family='Monospace', foreground = 'red')
  211.         buffer.create_tag('chat', family='Monospace')
  212.         #buffer.create_tag('output', family='Monospace', weight = pango.WEIGHT_BOLD)
  213.         #buffer.create_tag('move', family='Monospace', foreground = 'blue')
  214.         buffer.create_tag('info', family='Monospace', foreground = 'gray')
  215.         #buffer.create_tag('error', family='Monospace', foreground = 'red')
  216.         buffer.create_mark('end', buffer.get_end_iter())
  217.         
  218.         mainUI.setTooltipStyle(self.__gui.get_widget('info_panel'))
  219.         
  220.         self.__addProfileDialog = GtkNetworkAddDialog(self, self.__gui.get_widget('network_game_dialog'))
  221.  
  222.     # Extended methods
  223.         
  224.     def setVisible(self, isVisible):
  225.         """Called by glchess.ui.NetworkController"""
  226.         widget = self.__gui.get_widget('network_game_dialog')
  227.         if isVisible:
  228.             widget.present()
  229.             
  230.             # Prompt for new profile if none configured
  231.             # FIXME: Make this clearer this is the count of non-profile elements in the combo
  232.             if len(self.profileModel) <= (self.profileModelSuffixCount + 1):
  233.                 self.__addProfileDialog.setVisible(True)
  234.         else:
  235.             self.__addProfileDialog.setVisible(False)
  236.             widget.hide()
  237.             
  238.     def setSensitive(self, isSensitive):
  239.         widget = self.__gui.get_widget('controls_box')
  240.         widget.set_sensitive(isSensitive)
  241.  
  242.     def setError(self, title, description):
  243.         self.__gui.get_widget('info_panel_title').set_markup('<big><b>%s</b></big>' % title)
  244.         self.__gui.get_widget('info_panel_description').set_markup('<i>%s</i>' % description)
  245.         self.__gui.get_widget('info_panel').show()
  246.         
  247.     def clearError(self):
  248.         self.__gui.get_widget('info_panel').hide()
  249.  
  250.     def addProfile(self, profile, name, useNow = False):
  251.         """Called by glchess.ui.UIController"""
  252.         iter = self.profileModel.insert(len(self.profileModel) - self.profileModelSuffixCount)
  253.         self.profileModel.set(iter, 0, profile, 1, self._set_profile, 2, name)        
  254.         if self.__profile is None and useNow:
  255.             self.__gui.get_widget('server_combo').set_active_iter(iter)
  256.  
  257.     def setBusy(self, isBusy):
  258.         """Called by glchess.ui.UIController"""
  259.         if self._throbberTimer is not None:
  260.             gobject.source_remove(self._throbberTimer)
  261.             self._throbberTimer = None
  262.  
  263.         # Disable room buttons when busy
  264.         widget = self.__gui.get_widget('room_button_box')
  265.         widget.set_sensitive(not isBusy)
  266.         
  267.         # Display animating frames if busy or idle frame if not
  268.         if isBusy:
  269.             self._throbberFrame = 1
  270.             self._throbberTimer = gobject.timeout_add(25, self._updateThrobber)
  271.         else:
  272.             self._throbberFrame = 0
  273.         self._updateThrobber()
  274.  
  275.     def addRoom(self, index, name, nPlayers, description, room, protocol):
  276.         """Called by glchess.ui.UIController"""
  277.         try:
  278.             (icon, isSupported) = {None:       ('stock_people', True),
  279.                                    'Chess':    ('gnome-glchess', True),
  280.                                    'Reversi':  ('gnome-iagno', False),
  281.                                    'GGZCards': ('gnome-aisleriot', False),
  282.                                    'Gnect':    ('gnome-gnect', False),
  283.                                    'Gnibbles': ('gnome-gnibbles', False),
  284.                                    'Freeciv':  ('civclient', False)}[protocol]
  285.         except KeyError:
  286.             isSupported = False
  287.             icon = None
  288.             
  289.         if isSupported:
  290.             iter = self.roomModel.insert_before(None, self.firstNonChessIter)
  291.             style = pango.STYLE_NORMAL
  292.         else:
  293.             iter = self.roomModel.append(None)
  294.             if self.firstNonChessIter is None:
  295.                 self.firstNonChessIter = iter
  296.             style = pango.STYLE_ITALIC
  297.  
  298.         self.roomIters[room] = iter
  299.         self.roomModel.set(iter, 0, room, 1, index, 2, name, 3, nPlayers, 4, description, 5, pango.WEIGHT_NORMAL, 6, style, 7, icon)
  300.  
  301.     def enterRoom(self, room):
  302.         """Called by glchess.ui.UIController"""
  303.         for (r, iter) in self.roomIters.iteritems():
  304.             if r is room:
  305.                 weight = pango.WEIGHT_BOLD
  306.             else:
  307.                 weight = pango.WEIGHT_NORMAL
  308.             self.roomModel.set(iter, 5, weight)
  309.  
  310.     def updateRoom(self, room, nPlayers):
  311.         try:
  312.             iter = self.roomIters[room]
  313.         except KeyError:
  314.             print 'Unknown room!'
  315.             return
  316.         self.roomModel.set(iter, 3, nPlayers)
  317.     
  318.     def removeRoom(self, room):
  319.         """Called by glchess.ui.UIController"""
  320.         iter = self.roomModel.get_iter_first()
  321.         while iter is not None:
  322.             if room is self.roomModel.get_value(iter, 0):
  323.                 self.roomModel.remove(iter)
  324.                 return
  325.             iter = self.roomModel.iter_next(iter)
  326.  
  327.     def clearRooms(self):
  328.         """Called by glchess.ui.UIController"""
  329.         self.firstNonChessIter = None
  330.         self.roomIters = {}
  331.         self.roomModel.clear()
  332.     
  333.     def updateTable(self, table, name, seats, description, canConnect):
  334.         """Called by glchess.ui.UIController"""
  335.         try:
  336.             iter = self.tableIters[table]
  337.             seatModel = self.tableModel.get_value(iter, 4)
  338.         except KeyError:
  339.             iter = self.tableModel.append()
  340.             self.tableIters[table] = iter
  341.             seatModel = gtk.ListStore(int, str, str, str, int) # number, type, name, occupant, font style
  342.         self.tableModel.set(iter, 0, table, 1, name, 2, seats, 3, description, 4, seatModel, 5, canConnect)
  343.  
  344.     def updateSeat(self, table, number, type, name):
  345.         """Called by glchess.ui.UIController"""
  346.         iter = self.tableIters[table]
  347.         seatModel = self.tableModel.get_value(iter, 4)
  348.         iter = seatModel.get_iter_first()
  349.         while iter is not None:
  350.             if number == seatModel.get_value(iter, 0):
  351.                 break
  352.             iter = seatModel.iter_next(iter)
  353.         if iter is None:
  354.             iter = seatModel.append()
  355.             
  356.         if number == 0:
  357.             # Translators: GGZ seat is occupied by the white player
  358.             seatName = _('White')
  359.         elif number == 1:
  360.             # Translators: GGZ seat is occupied by the black player            
  361.             seatName = _('Black')
  362.         else:
  363.             # Translators: GGZ seat is occupied by a spectator
  364.             seatName = _('Spectator')
  365.  
  366.         style = pango.STYLE_ITALIC
  367.         occupant = name
  368.         if type == 'player':
  369.             style = pango.STYLE_NORMAL
  370.         elif type == 'reserved':
  371.             # Translators: GGZ seat status: This seat is reserved. %s is replaced with
  372.             # the name of the player the seat is reserved for.
  373.             occupant = _('Reserved for %s') % name
  374.         elif type == 'open':
  375.             # Translators: GGZ seat status: This seat is not taken
  376.             occupant = _('Seat empty')
  377.         elif type == 'bot':
  378.             # Translators: GGZ seat status: This seat contains an AI player.
  379.             # %s is replaced with the name of the AI.
  380.             occupant = _('AI (%s)') % name
  381.  
  382.         seatModel.set(iter, 0, number, 1, type, 2, seatName, 3, occupant, 4, style)
  383.  
  384.     def removeTable(self, table):
  385.         """Called by glchess.ui.UIController"""
  386.         iter = self.tableIters[table]
  387.         self.tableModel.remove(iter)
  388.             
  389.     def joinTable(self, table):
  390.         """Called by glchess.ui.UIController"""
  391.         gameFrame = self.__gui.get_widget('game_frame')
  392.         roomFrame = self.__gui.get_widget('room_frame')
  393.         if table is None:
  394.             gameFrame.hide()
  395.             roomFrame.show()
  396.         else:
  397.             iter = self.tableIters[table]
  398.             
  399.             seatModel = self.tableModel.get_value(iter, 4)
  400.             self.__gui.get_widget('seat_list').set_model(seatModel)
  401.             
  402.             name = self.tableModel.get_value(iter, 3)
  403.             self.__gui.get_widget('game_name_label').set_text(name)
  404.             roomFrame.hide()
  405.             gameFrame.show()
  406.  
  407.     def clearTables(self):
  408.         """Called by glchess.ui.UIController"""
  409.         self.tableIters = {}
  410.         self.tableModel.clear()
  411.  
  412.     def addPlayer(self, player, name, icon):
  413.         """Called by glchess.ui.UIController"""
  414.         iter = self.playerModel.append()
  415.         self.playerModel.set(iter, 0, player, 1, name, 2, icon)
  416.  
  417.     def removePlayer(self, player):
  418.         """Called by glchess.ui.UIController"""
  419.         iter = self.playerModel.get_iter_first()
  420.         while iter is not None:
  421.             if player is self.playerModel.get_value(iter, 0):
  422.                 self.playerModel.remove(iter)
  423.                 return
  424.             iter = self.playerModel.iter_next(iter)
  425.     
  426.     def clearPlayers(self):
  427.         """Called by glchess.ui.UIController"""
  428.         self.playerModel.clear()
  429.     
  430.     def addText(self, text, style):
  431.         """Called by glchess.ui.UIController"""
  432.         view = self.__gui.get_widget('chat_textview')
  433.         scroll = self.__gui.get_widget('chat_scroll_window')
  434.         adj = scroll.get_vadjustment()
  435.         atBottom = adj.value >= adj.upper - adj.page_size
  436.         buffer = view.get_buffer()
  437.         mark = buffer.get_mark('end')
  438.         buffer.insert_with_tags_by_name(buffer.get_iter_at_mark(mark), text, style)
  439.         if atBottom:
  440.             view.scroll_mark_onscreen(mark)
  441.  
  442.     def clearText(self):
  443.         buffer = self.__gui.get_widget('chat_textview').get_buffer()
  444.         buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
  445.  
  446.     def close(self):
  447.         """Called by glchess.ui.UIController"""
  448.         self.__gui.get_widget('network_game_dialog').hide()        
  449.  
  450.     # Private methods
  451.     
  452.     def __loadThrobber(self):
  453.         self._throbberTimer = None
  454.         theme = gtk.icon_theme_get_default()
  455.         size = 32
  456.         self._throbberFrames = []
  457.         
  458.         try:
  459.             icon = theme.load_icon('process-idle', size, 0)
  460.         except gobject.GError:
  461.             pass
  462.         else:
  463.             self._throbberFrames.append(icon)
  464.  
  465.         try:
  466.             icon = theme.load_icon('process-working', size, 0)
  467.         except gobject.GError:
  468.             pass
  469.         else:
  470.             # If a smaller icon was received than expected then use that size
  471.             height = icon.get_height()
  472.             width = icon.get_width()
  473.             size = min(size, height, width)
  474.  
  475.             for i in xrange(height / size):
  476.                 for j in xrange(width / size):
  477.                     frame = icon.subpixbuf(j * size, i * size, size, size)
  478.                     self._throbberFrames.append(frame)
  479.                 
  480.         # Display idle frame
  481.         self._throbberFrame = 0
  482.         self._updateThrobber()
  483.  
  484.     def _updateThrobber(self):
  485.         widget = self.__gui.get_widget('throbber_image')
  486.         try:
  487.             icon = self._throbberFrames[self._throbberFrame]
  488.         except IndexError:
  489.             pass
  490.         else:
  491.             widget.set_from_pixbuf(icon)
  492.         
  493.         # Move to next frame restarting animation after idle frame
  494.         self._throbberFrame += 1
  495.         if self._throbberFrame >= len(self._throbberFrames):
  496.             self._throbberFrame = 1
  497.         return True
  498.     
  499.     def __setCombo(self, comboName, key):
  500.         widget = self.__gui.get_widget(comboName)
  501.         iter = self.__getIter(widget.get_model(), key)
  502.         if iter is not None:
  503.             widget.set_active_iter(iter)
  504.     
  505.     def __getIter(self, model, key, default = None):
  506.         """
  507.         """
  508.         iter = model.get_iter_first()
  509.         while iter:
  510.             if model.get_value(iter, 0) == key:
  511.                 return iter
  512.  
  513.             iter = model.iter_next(iter)
  514.         return default
  515.                 
  516.     def __getComboData(self, comboBox, index):
  517.         """
  518.         """
  519.         model = comboBox.get_model()
  520.         iter = comboBox.get_active_iter()
  521.         if iter is None:
  522.             return None
  523.         
  524.         data = model.get(iter, index)
  525.         return data[0]
  526.        
  527.     def __startGame(self):
  528.         game = glchess.ui.Game()
  529.         game.name = self.__gui.get_widget('game_name_entry').get_text()
  530.         game.allowSpectators = True
  531.         
  532.         # Get the players
  533.         game.white.type  = self.__getComboData(self.__gui.get_widget('white_type_combo'), 0)
  534.         if game.white.type == '':
  535.             game.white.name = _('White')
  536.         else:
  537.             game.white.name = self.__getComboData(self.__gui.get_widget('white_type_combo'), 2)
  538.         game.white.level = self.__getComboData(self.__gui.get_widget('white_difficulty_combo'), 0)
  539.         game.black.type  = self.__getComboData(self.__gui.get_widget('black_type_combo'), 0)
  540.         if game.black.type == '':
  541.             game.black.name = _('Black')
  542.         else:
  543.             game.black.name = self.__getComboData(self.__gui.get_widget('black_type_combo'), 2)
  544.         game.black.level = self.__getComboData(self.__gui.get_widget('black_difficulty_combo'), 0)
  545.  
  546.         game.duration = self.__getComboData(self.__gui.get_widget('time_combo'), 1)
  547.         if game.duration < 0:
  548.             multiplier = self.__getComboData(self.__gui.get_widget('custom_time_units_combo'), 1)
  549.             game.duration = self.__getComboData(self.__gui.get_widget('custom_time_spin'), 1) * multiplier
  550.             
  551.         # Save properties
  552.         glchess.config.set('new_game_dialog/white/type', game.white.type)
  553.         glchess.config.set('new_game_dialog/white/difficulty', game.white.level)
  554.         glchess.config.set('new_game_dialog/black/type', game.black.type)
  555.         glchess.config.set('new_game_dialog/black/difficulty', game.black.level)
  556.  
  557.         # Inform the child class
  558.         self.__mainUI.feedback.onGameStart(game)
  559.         
  560.     def _is_profile_model_separator(self, model, iter):
  561.         return model.get(iter, 1)[0] is None
  562.  
  563.     def _set_profile(self, profile):
  564.         if profile != self.__profile:
  565.             self.__profile = profile
  566.             self.feedback.setProfile(profile)
  567.             
  568.     def __selectActiveProfile(self):
  569.         iter = self.profileModel.get_iter_first()
  570.         while iter is not None:
  571.             if self.__profile == self.profileModel.get_value(iter, 0):
  572.                 break
  573.             iter = self.profileModel.iter_next(iter)
  574.         self.__gui.get_widget('server_combo').set_active_iter(iter)
  575.  
  576.     def _new_profile(self, profile):
  577.         self.__selectActiveProfile()
  578.         self.__addProfileDialog.setVisible(True)
  579.  
  580.     # Gtk+ signal handlers
  581.     
  582.     def _on_table_selected(self, selection):
  583.         (model, iter) = selection.get_selected()
  584.         if iter is None:
  585.             isSensitive = False
  586.         else:
  587.             isSensitive = model.get_value(iter, 5)
  588.  
  589.         widget = self.__gui.get_widget('table_join_button')
  590.         widget.set_sensitive(isSensitive)
  591.         
  592.     def _on_table_list_activated(self):
  593.         pass
  594.     
  595.     def _on_server_combo_changed(self, widget):
  596.         """Gtk+ callback"""
  597.         model = widget.get_model()
  598.         iter = widget.get_active_iter()
  599.         (method,) = model.get(iter, 1)
  600.         (profile,) = model.get(iter, 0)
  601.         method(profile)
  602.  
  603.     def _on_chat_entry_activate(self, widget):
  604.         """Gtk+ callback"""
  605.         text = widget.get_text()
  606.         widget.set_text('')
  607.         self.feedback.sendChat(text)
  608.         
  609.     def _on_delete(self, widget, event):
  610.         # Hide; don't delete this window
  611.         return True
  612.  
  613.     def _on_response(self, widget, response_id):
  614.         """Gtk+ callback"""
  615.         self.__gui.get_widget('network_game_dialog').hide()
  616.  
  617.     def _on_room_changed(self, widget, path, column):
  618.         """Gtk+ callback"""
  619.         # FIXME: Only if allowed to enter room (state machine)
  620.         model = self.__gui.get_widget('room_list').get_model()
  621.         iter = model.get_iter(path)
  622.         if iter is None:
  623.             return True
  624.         room = model.get_value(iter, 0)
  625.         if room is not None:
  626.             self.feedback.enterRoom(room)
  627.         return True
  628.  
  629.     def _on_table_join_button_clicked(self, widget):
  630.         """Gtk+ callback"""
  631.         (model, iter) = self.__gui.get_widget('table_list').get_selection().get_selected()
  632.         if iter is None:
  633.             return
  634.         table = model.get_value(iter, 0)
  635.         self.feedback.joinTable(table)
  636.  
  637.     def _on_table_leave_button_clicked(self, widget):
  638.         """Gtk+ callback"""
  639.         self.feedback.leaveTable()
  640.  
  641.     def _on_table_new_button_clicked(self, widget):
  642.         """Gtk+ callback"""
  643.         self.feedback.startTable()
  644.