def reproduce_foobared_rendering (): from dialog_swallower import SwappableArea sgd = SudokuGameDisplay() sgd.set_bg_color('black') vb = Gtk.VBox() hb = Gtk.HBox() swallower = SwappableArea(hb) tb = Gtk.Toolbar() b = Gtk.ToolButton(stock_id = Gtk.STOCK_QUIT) b.connect('clicked', lambda x: window.hide() or Gtk.main_quit()) tb.add(b) def run_swallowed_dialog (*args): md = MessageDialog(title = "Bar", label = "Bar", sublabel = "Baz "*12) swallower.run_dialog(md) b2 = Gtk.ToolButton(label = 'Dialog') b2.connect('clicked', run_swallowed_dialog) tb.add(b2) vb.pack_start(tb, fill = False, expand = False) vb.pack_start(swallower, padding = 12) window.add(vb) window.show_all() from gtk_goodies.dialog_extras import MessageDialog md = MessageDialog(title = "Foo", label = "Foo", sublabel = "Bar "*12) swallower.run_dialog(md) hb.pack_start(sgd, padding = 6) game = '''1 8 4 2 0 0 0 0 0 0 6 0 0 0 9 1 2 0 0 2 0 0 8 0 0 0 0 0 1 8 0 5 0 0 0 0 9 0 0 0 0 0 0 0 3 0 0 0 0 1 0 6 5 0 0 0 0 0 9 0 0 8 0 0 5 7 1 0 0 0 9 0 0 0 0 0 0 3 5 4 7''' sgd.change_grid(game, 9)
def reproduce_foobared_rendering (): from sudoku import SudokuGrid, sample_open_sudoku from dialog_swallower import SwappableArea sgd = SudokuGameDisplay() sgd.set_bg_color('black') w = gtk.Window() w.connect('delete-event', gtk.main_quit) vb = gtk.VBox() hb = gtk.HBox() swallower = SwappableArea(hb) tb = gtk.Toolbar() b = gtk.ToolButton(stock_id=gtk.STOCK_QUIT) b.connect('clicked',lambda x: w.hide() or gtk.main_quit()) tb.add(b) def run_swallowed_dialog (*args): md = MessageDialog(title="Bar",label="Bar",sublabel="Baz "*12) swallower.run_dialog(md) b2 = gtk.ToolButton(label='Dialog') b2.connect('clicked',run_swallowed_dialog) tb.add(b2) vb.pack_start(tb,fill=False,expand=False) vb.pack_start(swallower,padding=12) w.add(vb) w.show_all() from gtk_goodies.dialog_extras import MessageDialog md = MessageDialog(title="Foo",label="Foo",sublabel="Bar "*12) swallower.run_dialog(md) hb.pack_start(sgd,padding=6) sgd.change_grid(SudokuGrid(sample_open_sudoku),9) gtk.main()
def reproduce_foobared_rendering(): from dialog_swallower import SwappableArea sgd = SudokuGameDisplay() sgd.set_bg_color('black') vb = gtk.VBox() hb = gtk.HBox() swallower = SwappableArea(hb) tb = gtk.Toolbar() b = gtk.ToolButton(stock_id=gtk.STOCK_QUIT) b.connect('clicked', lambda x: window.hide() or gtk.main_quit()) tb.add(b) def run_swallowed_dialog(*args): md = MessageDialog(title="Bar", label="Bar", sublabel="Baz " * 12) swallower.run_dialog(md) b2 = gtk.ToolButton(label='Dialog') b2.connect('clicked', run_swallowed_dialog) tb.add(b2) vb.pack_start(tb, fill=False, expand=False) vb.pack_start(swallower, padding=12) window.add(vb) window.show_all() from gtk_goodies.dialog_extras import MessageDialog md = MessageDialog(title="Foo", label="Foo", sublabel="Bar " * 12) swallower.run_dialog(md) hb.pack_start(sgd, padding=6) game = '''1 8 4 2 0 0 0 0 0 0 6 0 0 0 9 1 2 0 0 2 0 0 8 0 0 0 0 0 1 8 0 5 0 0 0 0 9 0 0 0 0 0 0 0 3 0 0 0 0 1 0 6 5 0 0 0 0 0 9 0 0 8 0 0 5 7 1 0 0 0 9 0 0 0 0 0 0 3 5 4 7''' sgd.change_grid(game, 9)
def setup_main_boxes (self): self.vb = gtk.VBox() # Add menu bar and toolbar... mb = self.uimanager.get_widget('/MenuBar') mb.show() self.vb.pack_start(mb, fill = False, expand = False) self.tb = self.uimanager.get_widget('/Toolbar') self.vb.pack_start(self.tb, fill = False, expand = False) self.main_area = gtk.HBox() self.swallower = SwappableArea(self.main_area) self.swallower.show() self.vb.pack_start(self.swallower, True, padding = 12) self.main_area.pack_start(self.gsd, padding = 6) self.main_actions.set_visible(True) self.game_box = gtk.VBox() self.main_area.show() self.vb.show() self.game_box.show() self.main_area.pack_start(self.game_box, False, padding = 12) self.statusbar = gtk.Statusbar() self.statusbar.show() self.vb.pack_end(self.statusbar, fill = False, expand = False) self.w.add(self.vb)
class UI (gconf_wrapper.GConfWrapper): ui = '''<ui> <menubar name="MenuBar"> <menu name="Game" action="Game"> <menuitem action="New"/> <separator/> <menuitem action="PuzzleInfo"/> <separator/> <menuitem action="Print"/> <menuitem action="PrintMany"/> <separator/> <menuitem action="Close"/> </menu> <menu action="Edit"> <menuitem action="Undo"/> <menuitem action="Redo"/> <separator/> <menuitem action="Clear"/> <menuitem action="ClearNotes"/> </menu> <menu action="View"> <menuitem action="FullScreen"/> <separator/> <menuitem action="ToggleToolbar"/> <menuitem action="ToggleHighlight"/> </menu> <menu action="Tools"> <menuitem action="ShowPossible"/> <menuitem action="AutofillCurrentSquare"/> <menuitem action="Autofill"/> <separator/> <menuitem action="AlwaysShowPossible"/> <menuitem action="ShowImpossibleImplications"/> <separator/> <menuitem action="Generator"/> <menuitem action="BackgroundGenerator"/> <separator/> <menuitem action="Tracker"/> </menu> <menu action="Help"> <menuitem action="ShowHelp"/> <menuitem action="About"/> </menu> </menubar> <toolbar name="Toolbar"> <toolitem action="New"/> <toolitem action="Print"/> <separator/> <toolitem action="Undo"/> <toolitem action="Redo"/> <separator/> <toolitem action="ShowPossible"/> <toolitem action="AutofillCurrentSquare"/> <separator/> <toolitem action="ToggleHighlight"/> <toolitem action="Tracker"/> </toolbar> </ui>''' initial_prefs = {'group_size':9, 'always_show_hints':0, 'player':os.environ.get('USERNAME', ''), 'difficulty':0.0, 'minimum_number_of_new_puzzles':MIN_NEW_PUZZLES, 'highlight':0, 'bg_black':1, 'bg_custom_color':'', 'show_tracker':False, 'width': 700, 'height': 675, 'auto_save_interval':60 # auto-save interval in seconds... } @simple_debug def __init__ (self, run_selector = True): """run_selector means that we start our regular game. For testing purposes, it will be convenient to hand a run_selector=False to this method to avoid running the dialog and allow a tester to set up a game programmatically. """ gconf_wrapper.GConfWrapper.__init__(self, gconf_wrapper.GConf('gnome-sudoku') ) self.setup_gui() self.timer = ActiveTimer(self.w) self.won = False # add the accelerator group to our toplevel window self.worker_connections = [] # setup sudoku maker... self.sudoku_maker = sudoku_maker.SudokuMaker() self.sudoku_tracker = saver.SudokuTracker() # generate puzzles while our use is working... self.show() if run_selector: self.do_stop() if self.select_game(): # If this return True, the user closed... self.quit = True else: self.quit = False # Generate puzzles in background... if self.gconf['generate_puzzles_in_background']: gobject.timeout_add_seconds(1, lambda *args: self.start_worker_thread() and True) @inactivate_new_game_etc def select_game (self): self.tb.hide() self.update_statusbar() choice = game_selector.NewOrSavedGameSelector().run_swallowed_dialog(self.swallower) if not choice: return True self.timer.start_timing() if choice[0] == game_selector.NewOrSavedGameSelector.NEW_GAME: self.gsd.change_grid(choice[1], 9) self.update_statusbar() if choice[0] == game_selector.NewOrSavedGameSelector.SAVED_GAME: saver.open_game(self, choice[1]) self.update_statusbar() if self.gconf['show_toolbar']: self.tb.show() if self.gconf['always_show_hints']: self.gsd.update_all_hints() if self.gconf['highlight']: self.gsd.toggle_highlight(True) def show (self): self.gsd.show() self.w.show() def setup_gui (self): self.initialize_prefs() self.setup_main_window() self.gsd = gsudoku.SudokuGameDisplay() self.gsd.connect('puzzle-finished', self.you_win_callback) self.setup_color() self.setup_actions() self.setup_undo() self.setup_autosave() self.w.add_accel_group(self.uimanager.get_accel_group()) self.setup_main_boxes() self.setup_tracker_interface() self.setup_toggles() def setup_main_window (self): gtk.window_set_default_icon_name('gnome-sudoku') self.w = gtk.Window() self.w.set_default_size(self.gconf['width'], self.gconf['height']) self.w.set_title(APPNAME_SHORT) self.w.connect('configure-event', self.resize_cb) self.w.connect('delete-event', self.quit_cb) self.uimanager = gtk.UIManager() def setup_actions (self): self.main_actions = gtk.ActionGroup('MainActions') self.main_actions.add_actions([ ('Game', None, _('_Game')), ('New', gtk.STOCK_NEW, None, '<Control>n', _('New game'), self.new_cb), ('Print', gtk.STOCK_PRINT, None, None, _('Print current game'), self.print_game), ('PrintMany', gtk.STOCK_PRINT, _('Print _Multiple Sudokus'), None, _('Print more than one sudoku at a time.'), self.print_multiple_games), ('Close', gtk.STOCK_CLOSE, None, '<Control>w', _('Close Sudoku'), self.quit_cb), ('Tools', None, _('_Tools')), ('View', None, _('_View')), ('ShowPossible', gtk.STOCK_DIALOG_INFO, _('_Hint'), '<Control>h', _('Show which numbers could go in the current square.'), self.show_hint_cb), ('AutofillCurrentSquare', gtk.STOCK_APPLY, _('_Fill'), '<Control>f', _('Automatically fill in the current square if possible.'), self.auto_fill_current_square_cb), ('Autofill', gtk.STOCK_REFRESH, _('Fill _all squares'), '<Control>a', _('Automatically fill in all squares for which there is only one valid value.'), self.auto_fill_cb), ('FullScreen', gtk.STOCK_FULLSCREEN, None, 'F11', None, self.full_screen_cb), ('Generator', None, _('_Generate new puzzles'), None, _('Generate new puzzles.'), self.generate_puzzle_gui, ), ('PuzzleInfo', gtk.STOCK_ABOUT, _('Puzzle _Statistics'), None, _('Show statistics about current puzzle'), self.show_info_cb), ('Help', None, _('_Help'), None, None, None), ('About', gtk.STOCK_ABOUT, None, None, None, self.show_about), ('ShowHelp', gtk.STOCK_HELP, _('_Contents'), 'F1', None, self.show_help), ]) self.main_actions.add_toggle_actions([ ('AlwaysShowPossible', None, _('_Always show hint'), None, _('Always show possible numbers in a square'), self.auto_hint_cb), ('ShowImpossibleImplications', None, _('Warn about _unfillable squares'), None, _('Warn about squares made unfillable by a move'), self.impossible_implication_cb), ('Tracker', 'tracks', _('_Track additions'), '<Control>T', _('Mark new additions in a separate color so you can keep track of them.'), self.tracker_toggle_cb, False), ('ToggleToolbar', None, _('Show _Toolbar'), None, None, self.toggle_toolbar_cb, True), ('ToggleHighlight', gtk.STOCK_SELECT_COLOR, _('_Highlighter'), None, _('Highlight the current row, column and box'), self.toggle_highlight_cb, False), ('BackgroundGenerator', None, _('Generate new puzzles _while you play'), None, _('Generate new puzzles in the background while you play. This will automatically pause when the game goes into the background.'), self.toggle_generator_cb, True), ]) self.edit_actions = gtk.ActionGroup('EditActions') self.edit_actions.add_actions( [('Edit', None, _('_Edit')), ('Undo', gtk.STOCK_UNDO, _('_Undo'), '<Control>z', _('Undo last action'), self.stop_dancer), ('Redo', gtk.STOCK_REDO, _('_Redo'), '<Shift><Control>z', _('Redo last action')), ('Clear', gtk.STOCK_CLEAR, _('_Clear'), '<Control>b', _("Clear entries you've filled in"), self.clear_cb), ('ClearNotes', None, _('Clear _Notes'), None, _("Clear notes and hints"), self.clear_notes_cb), ]) self.uimanager.insert_action_group(self.main_actions, 0) self.uimanager.insert_action_group(self.edit_actions, 0) self.uimanager.add_ui_from_string(self.ui) def setup_undo (self): self.cleared = [] # used for Undo memory self.cleared_notes = [] # used for Undo memory # Set up our UNDO stuff undo_widg = self.edit_actions.get_action('Undo') redo_widg = self.edit_actions.get_action('Redo') self.history = Undo.UndoHistoryList(undo_widg, redo_widg) for entry in self.gsd.__entries__.values(): Undo.UndoableGenericWidget(entry, self.history, set_method = 'set_value_from_undo', pre_change_signal = 'value-about-to-change' ) Undo.UndoableGenericWidget(entry, self.history, set_method = 'set_notes', get_method = 'get_note_text', signal = 'notes-changed', pre_change_signal = 'value-about-to-change', ) def setup_color (self): # setup background colors if self.gconf['bg_custom_color']: bgcol = self.gconf['bg_custom_color'] elif self.gconf['bg_black']: bgcol = 'black' else: bgcol = None if bgcol: self.gsd.set_bg_color(bgcol) def setup_autosave (self): gobject.timeout_add_seconds(self.gconf['auto_save_interval'] or 60, # in seconds... self.autosave) def setup_main_boxes (self): self.vb = gtk.VBox() # Add menu bar and toolbar... mb = self.uimanager.get_widget('/MenuBar') mb.show() self.vb.pack_start(mb, fill = False, expand = False) self.tb = self.uimanager.get_widget('/Toolbar') self.vb.pack_start(self.tb, fill = False, expand = False) self.main_area = gtk.HBox() self.swallower = SwappableArea(self.main_area) self.swallower.show() self.vb.pack_start(self.swallower, True, padding = 12) self.main_area.pack_start(self.gsd, padding = 6) self.main_actions.set_visible(True) self.game_box = gtk.VBox() self.main_area.show() self.vb.show() self.game_box.show() self.main_area.pack_start(self.game_box, False, padding = 12) self.statusbar = gtk.Statusbar() self.statusbar.show() self.vb.pack_end(self.statusbar, fill = False, expand = False) self.w.add(self.vb) def setup_toggles (self): # sync up toggles with gconf values... map(lambda tpl: self.gconf_wrap_toggle(*tpl), [('always_show_hints', self.main_actions.get_action('AlwaysShowPossible')), ('show_impossible_implications', self.main_actions.get_action('ShowImpossibleImplications')), ('generate_puzzles_in_background', self.main_actions.get_action('BackgroundGenerator')), ('show_toolbar', self.main_actions.get_action('ToggleToolbar')), ('highlight', self.main_actions.get_action('ToggleHighlight')), ('show_tracker', self.main_actions.get_action('Tracker')), ]) @simple_debug def start_worker_thread (self, *args): n_new_puzzles = self.sudoku_maker.n_puzzles(new = True) if n_new_puzzles < self.gconf['minimum_number_of_new_puzzles']: self.worker = threading.Thread(target = lambda *args: self.sudoku_maker.work(limit = 5)) self.worker_connections = [ self.timer.connect('timing-started', self.sudoku_maker.resume), self.timer.connect('timing-stopped', self.sudoku_maker.pause) ] self.worker.start() return True @simple_debug def stop_worker_thread (self, *args): if hasattr(self, 'worker'): self.sudoku_maker.stop() for c in self.worker_connections: self.timer.disconnect(c) def stop_dancer (self, *args): if hasattr(self, 'dancer'): self.dancer.stop_dancing() delattr(self, 'dancer') @simple_debug def you_win_callback (self, grid): if hasattr(self, 'dancer'): return self.won = True # increase difficulty for next time. self.gconf['difficulty'] = self.gconf['difficulty'] + 0.1 self.timer.finish_timing() self.sudoku_tracker.finish_game(self) sublabel = _("You completed the puzzle in %(totalTime)s (%(activeTime)s active)") % {'totalTime': self.timer.total_time_string(), 'activeTime': self.timer.active_time_string() } sublabel += "\n" sublabel += ngettext("You got %(n)s hint", "You got %(n)s hints", self.gsd.hints) % {'n':self.gsd.hints} sublabel += "\n" if self.gsd.impossible_hints: sublabel += ngettext("You had %(n)s impossibility pointed out.", "You had %(n)s impossibilities pointed out.", self.gsd.impossible_hints) % {'n':self.gsd.impossible_hints} sublabel += "\n" if self.gsd.auto_fills: sublabel += ngettext("You used the auto-fill %(n)s time", "You used the auto-fill %(n)s times", self.gsd.auto_fills) % {'n':self.gsd.auto_fills} import dancer self.dancer = dancer.GridDancer(self.gsd) self.dancer.start_dancing() dialog_extras.show_message(_("You win!"), label = _("You win!"), sublabel = sublabel ) @simple_debug def initialize_prefs (self): for k, v in self.initial_prefs.items(): try: self.gconf[k] except: self.gconf[k] = v self.player = self.gconf['player'] @simple_debug @inactivate_new_game_etc def new_cb (self, *args): if (self.gsd.grid and self.gsd.grid.is_changed() and not self.won): try: if dialog_extras.getBoolean( label = _("Save this game before starting new one?"), custom_yes = _("_Save game for later"), custom_no = _("_Abandon game"), ): self.save_game() else: self.sudoku_tracker.abandon_game(self) except dialog_extras.UserCancelledError: # User cancelled new game return self.do_stop() self.select_game() @simple_debug def stop_game (self): if (self.gsd.grid and self.gsd.grid.is_changed() and (not self.won)): try: if dialog_extras.getBoolean(label = _("Save game before closing?")): self.save_game(self) except dialog_extras.UserCancelledError: return self.do_stop() def do_stop (self): self.stop_dancer() self.gsd.grid = None self.tracker_ui.reset() self.history.clear() self.won = False @simple_debug def resize_cb (self, widget, event): self.gconf['width'] = event.width self.gconf['height'] = event.height @simple_debug def quit_cb (self, *args): self.w.hide() if (self.gsd.grid and self.gsd.grid.is_changed() and (not self.won)): self.save_game(self) if gtk.main_level() > 1: # If we are in an embedded mainloop, that means that one # of our "swallowed" dialogs is active, in which case we # have to quit that mainloop before we can quit # properly. if self.swallower.running: d = self.swallower.running d.response(gtk.RESPONSE_DELETE_EVENT) gtk.main_quit() # Quit the embedded mainloop gobject.idle_add(self.quit_cb, 100) # Call ourselves again # to quit the main # mainloop return # make sure we really go away before doing our saving -- # otherwise we appear sluggish. while gtk.events_pending(): gtk.main_iteration() if self.won: self.gconf['current_game'] = '' if not self.won: if not self.gsd.grid: self.gconf['current_game'] = '' self.stop_worker_thread() # allow KeyboardInterrupts, which calls quit_cb outside the main loop try: gtk.main_quit() except RuntimeError: pass @simple_debug def save_game (self, *args): self.sudoku_tracker.save_game(self) def full_screen_cb (self, *args): if not hasattr(self, 'is_fullscreen'): self.is_fullscreen = False if self.is_fullscreen: self.w.unfullscreen() self.is_fullscreen = False else: self.w.fullscreen() self.is_fullscreen = True @simple_debug def clear_cb (self, *args): clearer = Undo.UndoableObject( self.do_clear, #action self.undo_clear, #inverse self.history #history ) clearer.perform() # add a check to stop the dancer if she is dancing def do_clear (self, *args): self.cleared.append(self.gsd.reset_grid()) self.stop_dancer() # add a check for finish in the undo to clear def undo_clear (self, *args): for entry in self.cleared.pop(): self.gsd.add_value(*entry) if self.gsd.grid.check_for_completeness(): self.gsd.emit('puzzle-finished') def clear_notes_cb (self, *args): clearer = Undo.UndoableObject( lambda *args: self.cleared_notes.append(self.gsd.clear_notes()), #action # clear_notes returns a list of tuples indicating the cleared notes... # (x,y,(top,bottom)) -- this is what we need for undoing lambda *args: [self.gsd.__entries__[t[0], t[1]].set_notes(t[2]) for t in self.cleared_notes.pop()], #inverse self.history ) clearer.perform() @simple_debug def show_hint_cb (self, *args): self.gsd.show_hint() @simple_debug def auto_hint_cb (self, action): if action.get_active(): self.gsd.always_show_hints = True self.gsd.update_all_hints() else: self.gsd.always_show_hints = False self.gsd.clear_hints() @simple_debug def impossible_implication_cb (self, action): if action.get_active(): self.gsd.show_impossible_implications = True else: self.gsd.show_impossible_implications = False @simple_debug def auto_fill_cb (self, *args): if not hasattr(self, 'autofilled'): self.autofilled = [] if not hasattr(self, 'autofiller'): self.autofiller = Undo.UndoableObject( self.do_auto_fill, self.undo_auto_fill, self.history ) self.autofiller.perform() def do_auto_fill (self, *args): self.autofilled.append(self.gsd.auto_fill()) if self.gconf['always_show_hints']: self.gsd.update_all_hints() def undo_auto_fill (self, *args): for entry in self.autofilled.pop(): self.gsd.remove(entry[0], entry[1], do_removal = True) if self.gconf['always_show_hints']: self.gsd.update_all_hints() @simple_debug def auto_fill_current_square_cb (self, *args): self.gsd.auto_fill_current_entry() @simple_debug def setup_tracker_interface (self): self.trackers = {} self.tracker_ui = TrackerBox(self) self.tracker_ui.show_all() self.tracker_ui.hide() self.game_box.add(self.tracker_ui) @simple_debug def tracker_toggle_cb (self, widg): if widg.get_active(): self.tracker_ui.show_all() else: self.tracker_ui.hide() @simple_debug def toggle_toolbar_cb (self, widg): if widg.get_active(): self.tb.show() else: self.tb.hide() def set_statusbar_value (self, status): if not hasattr(self, 'sbid'): self.sbid = self.statusbar.get_context_id('game_info') self.statusbar.pop(self.sbid) self.statusbar.push(self.sbid, status) def update_statusbar (self, *args): if not self.gsd.grid: self.set_statusbar_value(" ") return True puzzle = self.gsd.grid.virgin.to_string() puzzle_diff = self.sudoku_maker.get_difficulty(puzzle) tot_string = _("Playing %(difficulty)s puzzle.") % {'difficulty':puzzle_diff.value_string()} tot_string += " " + "(%1.2f)" % puzzle_diff.value self.set_statusbar_value(tot_string) return True def toggle_highlight_cb (self, widg): if widg.get_active(): self.gsd.toggle_highlight(True) else: self.gsd.toggle_highlight(False) @simple_debug def show_info_cb (self, *args): if not self.gsd.grid: dialog_extras.show_message(parent = self.w, title = _("Puzzle Information"), label = _("There is no current puzzle.") ) return puzzle = self.gsd.grid.virgin.to_string() diff = self.sudoku_maker.get_difficulty(puzzle) information = _("Calculated difficulty: ") information += diff.value_string() information += " (%1.2f)" % diff.value information += "\n" information += _("Number of moves instantly fillable by elimination: ") information += str(int(diff.instant_elimination_fillable)) information += "\n" information += _("Number of moves instantly fillable by filling: ") information += str(int(diff.instant_fill_fillable)) information += "\n" information += _("Amount of trial-and-error required to solve: ") information += str(len(diff.guesses)) dialog_extras.show_message(parent = self.w, title = _("Puzzle Statistics"), label = _("Puzzle Statistics"), sublabel = information) @simple_debug def toggle_generator_cb (self, toggle): if toggle.get_active(): self.start_worker_thread() else: self.stop_worker_thread() @simple_debug def autosave (self): # this is called on a regular loop and will autosave if we # have reason to... if self.gsd.grid and self.gsd.grid.is_changed() and not self.won: self.sudoku_tracker.save_game(self) return True @simple_debug def show_about (self, *args): about = gtk.AboutDialog() about.set_transient_for(self.w) about.set_name(APPNAME) about.set_version(VERSION) about.set_copyright(COPYRIGHT) about.set_license(LICENSE[0] + '\n\n' + LICENSE[1] + '\n\n' + LICENSE[2]) about.set_wrap_license(True) about.set_comments(DESCRIPTION) about.set_authors(AUTHORS) about.set_website(WEBSITE) about.set_website_label(WEBSITE_LABEL) about.set_logo_icon_name("gnome-sudoku") about.set_translator_credits(_("translator-credits")) about.connect("response", lambda d, r: d.destroy()) about.show() @simple_debug def show_help (self, *args): try: gtk.show_uri(self.w.get_screen(), "ghelp:gnome-sudoku", gtk.get_current_event_time()) except gobject.GError, error: # FIXME: This should create a pop-up dialog print _('Unable to display help: %s') % str(error)