Beispiel #1
0
    def handleArgs(self, chess_file):
        if chess_file:

            def do(discoverer):
                GLib.idle_add(newGameDialog.LoadFileExtension.run, chess_file)

            discoverer.connect_after("all_engines_discovered", do)
Beispiel #2
0
    def handleArgs(self, chess_file):
        if chess_file:

            def do(discoverer):
                GLib.idle_add(newGameDialog.LoadFileExtension.run, chess_file)

            discoverer.connect_after("all_engines_discovered", do)
Beispiel #3
0
    def __init__(self):
        #GObject.GObject.__init__(self,0,0,0,0)
        GObject.GObject.__init__(self)
        self.widgets = widgets = uistuff.GladeWidgets("taskers.glade")
        tasker = widgets["newGameTasker"]
        tasker.unparent()
        self.add(tasker)

        combo = ToggleComboBox()
        combo.addItem(_("White"), get_pixbuf("glade/white.png"))
        combo.addItem(_("Black"), get_pixbuf("glade/black.png"))
        combo.addItem(_("Random"), get_pixbuf("glade/random.png"))
        combo.setMarkup("<b>", "</b>")
        widgets["colorDock"].add(combo)
        uistuff.keep(combo, "newgametasker_colorcombo")
        widgets['yourColorLabel'].set_mnemonic_widget(combo)

        # We need to wait until after engines have been discovered, to init the
        # playerCombos. We use connect_after to make sure, that newGameDialog
        # has also had time to init the constants we share with them.
        self.playerCombo = ToggleComboBox()
        widgets["opponentDock"].add(self.playerCombo)
        discoverer.connect_after("all_engines_discovered",
                                 self.__initPlayerCombo, widgets)
        widgets['opponentLabel'].set_mnemonic_widget(self.playerCombo)

        def on_skill_changed(scale):
            pix = newGameDialog.skillToIconLarge[int(scale.get_value())]
            widgets["skillImage"].set_from_pixbuf(pix)

        widgets["skillSlider"].connect("value-changed", on_skill_changed)
        on_skill_changed(widgets["skillSlider"])

        widgets["startButton"].connect("clicked", self.startClicked)
        self.widgets["opendialog1"].connect("clicked", self.openDialogClicked)
Beispiel #4
0
    def __init__(self):
        #GObject.GObject.__init__(self,0,0,0,0)
        GObject.GObject.__init__(self)
        self.widgets = widgets = uistuff.GladeWidgets("taskers.glade")
        tasker = widgets["newGameTasker"]
        tasker.unparent()
        self.add(tasker)

        combo = ToggleComboBox()
        combo.addItem(_("White"), get_pixbuf("glade/white.png"))
        combo.addItem(_("Black"), get_pixbuf("glade/black.png"))
        combo.addItem(_("Random"), get_pixbuf("glade/random.png"))
        combo.setMarkup("<b>", "</b>")
        widgets["colorDock"].add(combo)
        uistuff.keep(combo, "newgametasker_colorcombo")
        widgets['yourColorLabel'].set_mnemonic_widget(combo)

        # We need to wait until after engines have been discovered, to init the
        # playerCombos. We use connect_after to make sure, that newGameDialog
        # has also had time to init the constants we share with them.
        self.playerCombo = ToggleComboBox()
        widgets["opponentDock"].add(self.playerCombo)
        discoverer.connect_after("all_engines_discovered",
                                 self.__initPlayerCombo, widgets)
        widgets['opponentLabel'].set_mnemonic_widget(self.playerCombo)

        def on_skill_changed(scale):
            pix = newGameDialog.skillToIconLarge[int(scale.get_value())]
            widgets["skillImage"].set_from_pixbuf(pix)

        widgets["skillSlider"].connect("value-changed", on_skill_changed)
        on_skill_changed(widgets["skillSlider"])

        widgets["startButton"].connect("clicked", self.startClicked)
        self.widgets["opendialog1"].connect("clicked", self.openDialogClicked)
Beispiel #5
0
    def handleArgs(self, chess_file):
        if chess_file:

            def do(discoverer):
                perspective = perspective_manager.get_perspective("database")
                GLib.idle_add(perspective.open_chessfile, chess_file)

            discoverer.connect_after("all_engines_discovered", do)
Beispiel #6
0
    def handleArgs(self, chess_file):
        if chess_file:

            def do(discoverer):
                perspective = perspective_manager.get_perspective("database")
                perspective.open_chessfile(chess_file)
                self.dd_task.cancel()

            discoverer.connect_after("all_engines_discovered", do)
Beispiel #7
0
    def handleArgs(self, chess_file):
        if chess_file:

            def do(discoverer):
                perspective = perspective_manager.get_perspective("database")
                perspective.open_chessfile(chess_file)
                self.dd_task.cancel()

            discoverer.connect_after("all_engines_discovered", do)
Beispiel #8
0
    def __init__(self):
        GObject.GObject.__init__(self)
        self.widgets = widgets = tasker_widgets
        tasker = widgets["newGameTasker"]
        tasker.unparent()
        self.add(tasker)

        startButton = self.widgets["startButton"]
        startButton.set_name("startButton")
        combo = Gtk.ComboBox()
        uistuff.createCombo(
            combo,
            [
                (get_pixbuf("glade/white.png"), _("White")),
                (get_pixbuf("glade/black.png"), _("Black")),
                (get_pixbuf("glade/random.png"), _("Random")),
            ],
        )
        widgets["colorDock"].add(combo)
        if combo.get_active() < 0:
            combo.set_active(0)
        widgets["yourColorLabel"].set_mnemonic_widget(combo)

        # We need to wait until after engines have been discovered, to init the
        # playerCombos. We use connect_after to make sure, that newGameDialog
        # has also had time to init the constants we share with them.
        self.playerCombo = Gtk.ComboBox()
        widgets["opponentDock"].add(self.playerCombo)
        discoverer.connect_after("all_engines_discovered",
                                 self.__initPlayerCombo, widgets)
        widgets["opponentLabel"].set_mnemonic_widget(self.playerCombo)

        def on_skill_changed(scale):
            # Just to make sphinx happy...
            try:
                pix = newGameDialog.skillToIconLarge[int(scale.get_value())]
                widgets["skillImage"].set_from_pixbuf(pix)
            except TypeError:
                pass

        widgets["skillSlider"].connect("value-changed", on_skill_changed)
        on_skill_changed(widgets["skillSlider"])

        widgets["startButton"].connect("clicked", self.startClicked)
        self.widgets["opendialog1"].connect("clicked", self.openDialogClicked)
Beispiel #9
0
    def __init__(self):
        GObject.GObject.__init__(self)
        self.widgets = widgets = uistuff.GladeWidgets("taskers.glade")
        tasker = widgets["newGameTasker"]
        tasker.unparent()
        self.add(tasker)

        startButton = self.widgets["startButton"]
        startButton.set_name("startButton")
        combo = Gtk.ComboBox()
        uistuff.createCombo(combo, [
            (get_pixbuf("glade/white.png"), _("White")),
            (get_pixbuf("glade/black.png"), _("Black")),
            (get_pixbuf("glade/random.png"), _("Random"))])
        widgets["colorDock"].add(combo)
        if combo.get_active() < 0:
            combo.set_active(0)
        uistuff.keep(combo, "newgametasker_colorcombo")
        widgets['yourColorLabel'].set_mnemonic_widget(combo)

        # We need to wait until after engines have been discovered, to init the
        # playerCombos. We use connect_after to make sure, that newGameDialog
        # has also had time to init the constants we share with them.
        self.playerCombo = Gtk.ComboBox()
        widgets["opponentDock"].add(self.playerCombo)
        discoverer.connect_after("all_engines_discovered",
                                 self.__initPlayerCombo, widgets)
        widgets['opponentLabel'].set_mnemonic_widget(self.playerCombo)

        def on_skill_changed(scale):
            # Just to make sphinx happy...
            try:
                pix = newGameDialog.skillToIconLarge[int(scale.get_value())]
                widgets["skillImage"].set_from_pixbuf(pix)
            except TypeError:
                pass

        widgets["skillSlider"].connect("value-changed", on_skill_changed)
        on_skill_changed(widgets["skillSlider"])

        widgets["startButton"].connect("clicked", self.startClicked)
        self.widgets["opendialog1"].connect("clicked", self.openDialogClicked)
Beispiel #10
0
    def do_activate(self):
        # create_task(self.print_tasks())
        self.add_window(self.window)
        self.window.show_all()
        gamewidget.getWidgets()["player_rating1"].hide()
        gamewidget.getWidgets()["leave_fullscreen1"].hide()

        # Externals download dialog
        if not conf.get("dont_show_externals_at_startup"):
            externals_dialog = ExternalsDialog()
            externals_dialog.show()

        # Tip of the day dialog
        if conf.get("show_tip_at_startup"):
            tip_of_the_day = TipOfTheDay()
            tip_of_the_day.show()

        preferencesDialog.run(gamewidget.getWidgets())

        def on_all_engine_discovered(discoverer):
            engine = discoverer.getEngineByName(discoverer.getEngineLearn())
            if engine is None:
                engine = discoverer.getEngineN(-1)
            default_engine = engine.get("md5")
            conf.set("ana_combobox", default_engine)
            conf.set("inv_ana_combobox", default_engine)

        # Try to set conf analyzer engine on very first start of pychess
        if conf.get("ana_combobox") == 0:
            discoverer.connect_after("all_engines_discovered",
                                     on_all_engine_discovered)

        dd = DiscovererDialog(discoverer)
        self.dd_task = create_task(dd.start())

        style_ctxt = gamewidget.getWidgets()["main_window"].get_style_context()
        LIGHT = hexcol(style_ctxt.lookup_color("p_light_color")[1])
        DARK = hexcol(style_ctxt.lookup_color("p_dark_color")[1])
        conf.DEFAULTS["General"]["lightcolour"] = LIGHT
        conf.DEFAULTS["General"]["darkcolour"] = DARK

        self.splash.destroy()
Beispiel #11
0
 def protocol_changed(widget):
     if self.cur_engine is not None and not self.add and not self.selection:
         active = self.widgets["engine_protocol_combo"].get_active()
         new_protocol = "uci" if active==0 else "xboard"
         engine = discoverer.getEngineByName(self.cur_engine)
         old_protocol = engine["protocol"]
         if new_protocol != old_protocol:
             engine_command = engine_chooser_dialog.get_filename()
             # is the new protocol supported by the engine?
             if new_protocol == "uci":
                 ok = is_uci(engine_command)
             else:
                 ok = is_cecp(engine_command)
             if ok:
                 # discover engine options for new protocol
                 engine["protocol"] = new_protocol
                 engine["recheck"] = True
                 discoverer.connect_after("engine_discovered", update_options)
                 discoverer.discover()
             else:
                 # restore the original protocol
                 widgets["engine_protocol_combo"].set_active(0 if old_protocol=="uci" else 1)
Beispiel #12
0
    def do_activate(self):
        # create_task(self.print_tasks())
        self.add_window(self.window)
        self.window.show_all()
        gamewidget.getWidgets()["player_rating1"].hide()
        gamewidget.getWidgets()["leave_fullscreen1"].hide()

        # Externals download dialog
        if not conf.get("dont_show_externals_at_startup"):
            externals_dialog = ExternalsDialog()
            externals_dialog.show()

        # Tip of the day dialog
        if conf.get("show_tip_at_startup"):
            tip_of_the_day = TipOfTheDay()
            tip_of_the_day.show()

        preferencesDialog.run(gamewidget.getWidgets())

        def on_all_engine_discovered(discoverer):
            engine = discoverer.getEngineByName(discoverer.getEngineLearn())
            if engine is None:
                engine = discoverer.getEngineN(-1)
            default_engine = engine.get("md5")
            conf.set("ana_combobox", default_engine)
            conf.set("inv_ana_combobox", default_engine)

        # Try to set conf analyzer engine on very first start of pychess
        if conf.get("ana_combobox") == 0:
            discoverer.connect_after("all_engines_discovered", on_all_engine_discovered)

        dd = DiscovererDialog(discoverer)
        self.dd_task = create_task(dd.start())

        style_ctxt = gamewidget.getWidgets()["main_window"].get_style_context()
        LIGHT = hexcol(style_ctxt.lookup_color("p_light_color")[1])
        DARK = hexcol(style_ctxt.lookup_color("p_dark_color")[1])
        conf.set("lightcolour", LIGHT)
        conf.set("darkcolour", DARK)
Beispiel #13
0
        def add(button):
            self.add = True
            response = engine_chooser_dialog.run()

            if response == Gtk.ResponseType.OK:
                new_engine = engine_chooser_dialog.get_filename()
                if new_engine.lower().endswith(".exe") and sys.platform != "win32":
                    vm_name = "wine" 
                    vmpath = searchPath(vm_name, access=os.R_OK|os.X_OK)
                    if vmpath is None:
                        d = Gtk.MessageDialog(
                                type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
                        d.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                        d.format_secondary_text(_("wine not installed"))
                        d.run()
                        d.hide()
                        new_engine = ""
                    else:
                        vmpath += " "
                else:
                    vm_name = None
                    vmpath = ""
                
                if new_engine:
                    try:
                        uci = is_uci(vmpath + new_engine)
                        if not uci:
                            if not is_cecp(vmpath + new_engine):
                                # restore the original
                                engine = discoverer.getEngineByName(self.cur_engine)
                                engine_chooser_dialog.set_filename(engine["command"])
                                d = Gtk.MessageDialog(
                                        type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
                                d.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                                d.format_secondary_text(_("There is something wrong with this executable"))
                                d.run()
                                d.hide()
                                engine_chooser_dialog.hide()
                                return
                        path, binname = os.path.split(new_engine)
                        for e in discoverer.getEngines():
                            if e["name"] == binname:
                                binname = e["name"] + "(1)"
                                break
                        self.widgets["engine_command_entry"].set_text(new_engine)
                        self.widgets["engine_protocol_combo"].set_active(0 if uci else 1)
                        self.widgets["engine_args_entry"].set_text("")
                        
                        active = self.widgets["engine_protocol_combo"].get_active()
                        protocol = "uci" if active==0 else "xboard"
                        
                        discoverer.addEngine(binname, new_engine, protocol, vm_name)
                        self.cur_engine = binname
                        discoverer.connect_after("engine_discovered", update_store)
                        self.add = False
                        discoverer.discover()
                    except:
                        d = Gtk.MessageDialog(
                                type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
                        d.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                        d.format_secondary_text(_("There is something wrong with this executable"))
                        d.run()
                        d.hide()
                else:
                    # restore the original
                    engine = discoverer.getEngineByName(self.cur_engine)
                    engine_chooser_dialog.set_filename(engine["command"])
            engine_chooser_dialog.hide()
Beispiel #14
0
def initialize(gameDic):
    
    uistuff.keep(widgets["fromCurrent"], "fromCurrent", first_value=True)
    uistuff.keep(widgets["threatPV"], "threatPV")
    uistuff.keep(widgets["showEval"], "showEval")
    uistuff.keep(widgets["showBlunder"], "showBlunder", first_value=True)
    uistuff.keep(widgets["max_analysis_spin"], "max_analysis_spin", first_value=3)
    uistuff.keep(widgets["variation_thresold_spin"], "variation_thresold_spin", first_value=50)

    # Analyzing engines
    uistuff.createCombo(widgets["ana_combobox"])

    from pychess.widgets import newGameDialog
    @idle_add
    def update_analyzers_store(discoverer):
        data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
        uistuff.updateCombo(widgets["ana_combobox"], data)
    discoverer.connect_after("all_engines_discovered", update_analyzers_store)
    update_analyzers_store(discoverer)

    uistuff.keep(widgets["ana_combobox"], "ana_combobox", anal_combo_get_value,
        lambda combobox, value: anal_combo_set_value(combobox, value, "hint_mode",
                                              "analyzer_check", HINT))
 
    def hide_window(button, *args):
        widgets["analyze_game"].hide()
        return True
    
    def abort ():
        stop_event.set()
        widgets["analyze_game"].hide()
        
    def run_analyze(button, *args):
        gmwidg = gamewidget.cur_gmwidg()
        gamemodel = gameDic[gmwidg]

        old_check_value = conf.get("analyzer_check", True)
        conf.set("analyzer_check", True)
        analyzer = gamemodel.spectators[HINT]
        gmwidg.menuitems["hint_mode"].active = True
        threat_PV = conf.get("ThreatPV", False)
        if threat_PV:
            old_inv_check_value = conf.get("inv_analyzer_check", True)
            conf.set("inv_analyzer_check", True)
            inv_analyzer = gamemodel.spectators[SPY]
            gmwidg.menuitems["spy_mode"].active = True

        title = _("Game analyzing in progress...")
        text = _("Do you want to abort it?")
        content = InfoBar.get_message_content(title, text, Gtk.STOCK_DIALOG_QUESTION)
        def response_cb (infobar, response, message):
            message.dismiss()
            abort()
        message = InfoBarMessage(Gtk.MessageType.QUESTION, content, response_cb)
        message.add_button(InfoBarMessageButton(_("Abort"), Gtk.ResponseType.CANCEL))
        gmwidg.showMessage(message)

        def analyse_moves():
            from_current = conf.get("fromCurrent", True)
            start_ply = gmwidg.board.view.shown if from_current else 0
            move_time = int(conf.get("max_analysis_spin", 3))
            thresold = int(conf.get("variation_thresold_spin", 50))
            for board in gamemodel.boards[start_ply:]:
                if stop_event.is_set():
                    break
                @idle_add
                def do():
                    gmwidg.board.view.setShownBoard(board)
                do()
                analyzer.setBoard(board)
                inv_analyzer.setBoard(board)
                time.sleep(move_time+0.1)

                ply = board.ply
                if ply-1 in gamemodel.scores and ply in gamemodel.scores: 
                    color = (ply-1) % 2
                    oldmoves, oldscore, olddepth = gamemodel.scores[ply-1]
                    score_str = prettyPrintScore(oldscore, olddepth)
                    oldscore = oldscore * -1 if color == BLACK else oldscore
                    moves, score, depth = gamemodel.scores[ply]
                    score = score * -1 if color == WHITE else score
                    diff = score-oldscore
                    if (diff > thresold and color==BLACK) or (diff < -1*thresold and color==WHITE):
                        if threat_PV:
                            try:
                                if ply-1 in gamemodel.spy_scores:
                                    oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[ply-1]
                                    score_str0 = prettyPrintScore(oldscore0, olddepth0)
                                    pv0 = listToMoves(gamemodel.boards[ply-1], ["--"] + oldmoves0, validate=True)
                                    if len(pv0) > 2:
                                        gamemodel.add_variation(gamemodel.boards[ply-1], pv0, comment="Treatening", score=score_str0)
                            except ParsingError as e:
                                # ParsingErrors may happen when parsing "old" lines from
                                # analyzing engines, which haven't yet noticed their new tasks
                                log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % \
                                    (' '.join(oldmoves),e))
                        try:
                            pv = listToMoves(gamemodel.boards[ply-1], oldmoves, validate=True)
                            gamemodel.add_variation(gamemodel.boards[ply-1], pv, comment="Better is", score=score_str)
                        except ParsingError as e:
                            # ParsingErrors may happen when parsing "old" lines from
                            # analyzing engines, which haven't yet noticed their new tasks
                            log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % \
                                (' '.join(oldmoves),e))

            widgets["analyze_game"].hide()
            widgets["analyze_ok_button"].set_sensitive(True)
            conf.set("analyzer_check", old_check_value)
            if threat_PV:
                conf.set("inv_analyzer_check", old_inv_check_value)
            message.dismiss()
                        
        t = threading.Thread(target=analyse_moves, name=fident(analyse_moves))
        t.daemon = True
        t.start()
        hide_window(None)

        return True
    
    widgets["analyze_game"].connect("delete-event", hide_window)
    widgets["analyze_cancel_button"].connect("clicked", hide_window)
    widgets["analyze_ok_button"].connect("clicked", run_analyze)
Beispiel #15
0
    def _init(cls):
        cls.white = get_pixbuf("glade/white.png")
        cls.black = get_pixbuf("glade/black.png")

        cls.widgets = uistuff.GladeWidgets("newInOut.glade")
        cls.widgets["newgamedialog"].set_transient_for(mainwindow())

        def on_exchange_players(widget, button_event):
            white = cls.widgets["whitePlayerCombobox"].get_active()
            black = cls.widgets["blackPlayerCombobox"].get_active()
            whiteLevel = cls.widgets["skillSlider1"].get_value()
            blackLevel = cls.widgets["skillSlider2"].get_value()
            cls.widgets["whitePlayerCombobox"].set_active(black)
            cls.widgets["blackPlayerCombobox"].set_active(white)
            cls.widgets["skillSlider1"].set_value(blackLevel)
            cls.widgets["skillSlider2"].set_value(whiteLevel)

        cls.widgets["whitePlayerButton"].set_image(
            Gtk.Image.new_from_pixbuf(cls.white))
        cls.widgets["whitePlayerButton"].connect("button-press-event",
                                                 on_exchange_players)
        cls.widgets["blackPlayerButton"].set_image(
            Gtk.Image.new_from_pixbuf(cls.black))
        cls.widgets["blackPlayerButton"].connect("button-press-event",
                                                 on_exchange_players)

        uistuff.createCombo(cls.widgets["whitePlayerCombobox"],
                            name="whitePlayerCombobox")
        uistuff.createCombo(cls.widgets["blackPlayerCombobox"],
                            name="blackPlayerCombobox")

        cls.widgets["playersIcon"].set_from_pixbuf(big_people)
        cls.widgets["timeIcon"].set_from_pixbuf(big_time)

        def on_playerCombobox_changed(widget, skill_hbox):
            skill_hbox.props.visible = widget.get_active() > 0

        cls.widgets["whitePlayerCombobox"].connect("changed",
                                                   on_playerCombobox_changed,
                                                   cls.widgets["skillHbox1"])
        cls.widgets["blackPlayerCombobox"].connect("changed",
                                                   on_playerCombobox_changed,
                                                   cls.widgets["skillHbox2"])
        cls.widgets["whitePlayerCombobox"].set_active(0)
        cls.widgets["blackPlayerCombobox"].set_active(1)

        def on_skill_changed(scale, image):
            image.set_from_pixbuf(skillToIcon[int(scale.get_value())])

        cls.widgets["skillSlider1"].connect("value-changed", on_skill_changed,
                                            cls.widgets["skillIcon1"])
        cls.widgets["skillSlider2"].connect("value-changed", on_skill_changed,
                                            cls.widgets["skillIcon2"])
        cls.widgets["skillSlider1"].set_value(3)
        cls.widgets["skillSlider2"].set_value(3)

        cls.__initTimeRadio(_("Blitz"), "ngblitz", cls.widgets["blitzRadio"],
                            cls.widgets["configImageBlitz"], 5, 0, 0)
        cls.__initTimeRadio(_("Rapid"), "ngrapid", cls.widgets["rapidRadio"],
                            cls.widgets["configImageRapid"], 15, 5, 0)
        cls.__initTimeRadio(_("Normal"), "ngnormal",
                            cls.widgets["normalRadio"],
                            cls.widgets["configImageNormal"], 40, 15, 0)
        cls.__initTimeRadio(_("Classical"), "ngclassical",
                            cls.widgets["classicalRadio"],
                            cls.widgets["configImageClassical"], 3, 0, 40)

        cls.__initVariantRadio("ngvariant1", cls.widgets["playVariant1Radio"],
                               cls.widgets["configImageVariant1"],
                               FISCHERRANDOMCHESS)
        cls.__initVariantRadio("ngvariant2", cls.widgets["playVariant2Radio"],
                               cls.widgets["configImageVariant2"], LOSERSCHESS)

        def updateCombos(*args):
            if cls.widgets["playNormalRadio"].get_active():
                variant = NORMALCHESS
            elif cls.widgets["playVariant1Radio"].get_active():
                variant = conf.get("ngvariant1", FISCHERRANDOMCHESS)
            else:
                variant = conf.get("ngvariant2", LOSERSCHESS)
            variant1 = conf.get("ngvariant1", FISCHERRANDOMCHESS)
            cls.widgets["playVariant1Radio"].set_tooltip_text(
                variants[variant1].__desc__)
            variant2 = conf.get("ngvariant2", LOSERSCHESS)
            cls.widgets["playVariant2Radio"].set_tooltip_text(
                variants[variant2].__desc__)
            data = [(item[0], item[1]) for item in playerItems[variant]]
            uistuff.updateCombo(cls.widgets["blackPlayerCombobox"], data)
            uistuff.updateCombo(cls.widgets["whitePlayerCombobox"], data)

        discoverer.connect_after("all_engines_discovered", updateCombos)
        updateCombos(discoverer)

        conf.notify_add("ngvariant1", updateCombos)
        conf.notify_add("ngvariant2", updateCombos)
        cls.widgets["playNormalRadio"].connect("toggled", updateCombos)
        cls.widgets["playNormalRadio"].set_tooltip_text(
            variants[NORMALCHESS].__desc__)
        cls.widgets["playVariant1Radio"].connect("toggled", updateCombos)
        variant1 = conf.get("ngvariant1", FISCHERRANDOMCHESS)
        cls.widgets["playVariant1Radio"].set_tooltip_text(
            variants[variant1].__desc__)
        cls.widgets["playVariant2Radio"].connect("toggled", updateCombos)
        variant2 = conf.get("ngvariant2", LOSERSCHESS)
        cls.widgets["playVariant2Radio"].set_tooltip_text(
            variants[variant2].__desc__)

        # The "variant" has to come before players, because the engine positions
        # in the user comboboxes can be different in different variants
        for key in ("whitePlayerCombobox", "blackPlayerCombobox",
                    "skillSlider1", "skillSlider2", "notimeRadio",
                    "blitzRadio", "rapidRadio", "normalRadio",
                    "classicalRadio", "playNormalRadio", "playVariant1Radio",
                    "playVariant2Radio"):
            uistuff.keep(cls.widgets[key], key)

        # We don't want the dialog to deallocate when closed. Rather we hide
        # it on respond
        cls.widgets["newgamedialog"].connect("delete_event", lambda *a: True)
Beispiel #16
0
    def _init (cls):
        cls.widgets = uistuff.GladeWidgets ("newInOut.glade")

        uistuff.createCombo(cls.widgets["whitePlayerCombobox"], name="whitePlayerCombobox")
        uistuff.createCombo(cls.widgets["blackPlayerCombobox"], name="blackPlayerCombobox")

        cls.widgets["playersIcon"].set_from_pixbuf(big_people)
        cls.widgets["timeIcon"].set_from_pixbuf(big_time)


        def on_playerCombobox_changed (widget, skillHbox):
            skillHbox.props.visible = widget.get_active() > 0
        cls.widgets["whitePlayerCombobox"].connect(
                "changed", on_playerCombobox_changed, cls.widgets["skillHbox1"])
        cls.widgets["blackPlayerCombobox"].connect(
                "changed", on_playerCombobox_changed, cls.widgets["skillHbox2"])
        cls.widgets["whitePlayerCombobox"].set_active(0)
        cls.widgets["blackPlayerCombobox"].set_active(1)


        def on_skill_changed (scale, image):
            image.set_from_pixbuf(skillToIcon[int(scale.get_value())])
        cls.widgets["skillSlider1"].connect("value-changed", on_skill_changed,
                                            cls.widgets["skillIcon1"])
        cls.widgets["skillSlider2"].connect("value-changed", on_skill_changed,
                                            cls.widgets["skillIcon2"])
        cls.widgets["skillSlider1"].set_value(3)
        cls.widgets["skillSlider2"].set_value(3)


        cls.__initTimeRadio(_("Blitz"), "ngblitz", cls.widgets["blitzRadio"],
                            cls.widgets["configImageBlitz"], 5, 0)
        cls.__initTimeRadio(_("Rapid"), "ngrapid", cls.widgets["rapidRadio"],
                            cls.widgets["configImageRapid"], 15, 5)
        cls.__initTimeRadio(_("Normal"), "ngnormal", cls.widgets["normalRadio"],
                            cls.widgets["configImageNormal"], 40, 15)

        cls.__initVariantRadio("ngvariant1", cls.widgets["playVariant1Radio"],
                               cls.widgets["configImageVariant1"],
                               FISCHERRANDOMCHESS)
        cls.__initVariantRadio("ngvariant2", cls.widgets["playVariant2Radio"],
                               cls.widgets["configImageVariant2"], LOSERSCHESS)

        #@idle_add
        def updateCombos(*args):
            if cls.widgets["playNormalRadio"].get_active():
                variant = NORMALCHESS
            elif cls.widgets["playVariant1Radio"].get_active():
                variant = conf.get("ngvariant1", FISCHERRANDOMCHESS)
            else:
                variant = conf.get("ngvariant2", LOSERSCHESS)
            variant1 = conf.get("ngvariant1", FISCHERRANDOMCHESS)
            cls.widgets["playVariant1Radio"].set_tooltip_text(variants[variant1].__desc__)
            variant2 = conf.get("ngvariant2", LOSERSCHESS)
            cls.widgets["playVariant2Radio"].set_tooltip_text(variants[variant2].__desc__)
            data = [(item[0], item[1]) for item in playerItems[variant]]
            uistuff.updateCombo(cls.widgets["blackPlayerCombobox"], data)
            uistuff.updateCombo(cls.widgets["whitePlayerCombobox"], data)

        discoverer.connect_after("all_engines_discovered", updateCombos)
        updateCombos(discoverer)

        conf.notify_add("ngvariant1", updateCombos)
        conf.notify_add("ngvariant2", updateCombos)
        cls.widgets["playNormalRadio"].connect("toggled", updateCombos)
        cls.widgets["playNormalRadio"].set_tooltip_text(variants[NORMALCHESS].__desc__)
        cls.widgets["playVariant1Radio"].connect("toggled", updateCombos)
        variant1 = conf.get("ngvariant1", FISCHERRANDOMCHESS)
        cls.widgets["playVariant1Radio"].set_tooltip_text(variants[variant1].__desc__)
        cls.widgets["playVariant2Radio"].connect("toggled", updateCombos)
        variant2 = conf.get("ngvariant2", LOSERSCHESS)
        cls.widgets["playVariant2Radio"].set_tooltip_text(variants[variant2].__desc__)

        # The "variant" has to come before players, because the engine positions
        # in the user comboboxes can be different in different variants
        for key in ("whitePlayerCombobox", "blackPlayerCombobox",
                    "skillSlider1", "skillSlider2",
                    "notimeRadio", "blitzRadio", "rapidRadio", "normalRadio",
                    "playNormalRadio", "playVariant1Radio", "playVariant2Radio"):
            uistuff.keep(cls.widgets[key], key)

        # We don't want the dialog to deallocate when closed. Rather we hide
        # it on respond
        cls.widgets["newgamedialog"].connect("delete_event", lambda *a: True)
Beispiel #17
0
    def __init__(self, widgets):
        self.widgets = widgets

        # Options on by default
        for key in ("opening_check", "endgame_check", "online_egtb_check",
                    "analyzer_check", "inv_analyzer_check"):
            uistuff.keep(widgets[key], key, first_value=True)

        # Opening book
        default_path = os.path.join(addDataPrefix("pychess_book.bin"))
        path = conf.get("opening_file_entry", default_path)
        conf.set("opening_file_entry", path)

        book_chooser_dialog = Gtk.FileChooserDialog(
            _("Select book file"), mainwindow(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        book_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            book_chooser_dialog)

        filter = Gtk.FileFilter()
        filter.set_name(_("Opening books"))
        filter.add_pattern("*.bin")
        book_chooser_dialog.add_filter(filter)
        book_chooser_button.set_filename(path)

        self.widgets["bookChooserDock"].add(book_chooser_button)
        book_chooser_button.show()

        def select_new_book(button):
            new_book = book_chooser_dialog.get_filename()
            if new_book:
                conf.set("opening_file_entry", new_book)
            else:
                # restore the original
                book_chooser_dialog.set_filename(path)

        book_chooser_button.connect("file-set", select_new_book)

        def on_opening_check_toggled(check):
            self.widgets["opening_hbox"].set_sensitive(check.get_active())

        self.widgets["opening_check"].connect_after("toggled",
                                                    on_opening_check_toggled)

        # Endgame
        default_path = os.path.join(getDataPrefix())
        egtb_path = conf.get("egtb_path", default_path)
        conf.set("egtb_path", egtb_path)

        egtb_chooser_dialog = Gtk.FileChooserDialog(
            _("Select Gaviota TB path"), mainwindow(),
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        egtb_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            egtb_chooser_dialog)
        egtb_chooser_button.set_current_folder(egtb_path)

        self.widgets["egtbChooserDock"].add(egtb_chooser_button)
        egtb_chooser_button.show()

        def select_egtb(button):
            new_directory = egtb_chooser_dialog.get_filename()
            if new_directory != egtb_path:
                conf.set("egtb_path", new_directory)

        egtb_chooser_button.connect("current-folder-changed", select_egtb)

        def on_endgame_check_toggled(check):
            self.widgets["endgame_hbox"].set_sensitive(check.get_active())

        self.widgets["endgame_check"].connect_after("toggled",
                                                    on_endgame_check_toggled)

        # Analyzing engines
        from pychess.widgets import newGameDialog
        data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
        uistuff.createCombo(widgets["ana_combobox"], data, name="ana_combobox")
        uistuff.createCombo(widgets["inv_ana_combobox"],
                            data,
                            name="inv_ana_combobox")

        def update_analyzers_store(discoverer):
            data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
            uistuff.updateCombo(widgets["ana_combobox"], data)
            uistuff.updateCombo(widgets["inv_ana_combobox"], data)

        discoverer.connect_after("all_engines_discovered",
                                 update_analyzers_store)
        update_analyzers_store(discoverer)

        # Save, load and make analyze combos active

        # Let Stockfish to be default analyzer in Windows installer
        default = discoverer.getEngineN(-1).get("md5")
        conf.set("ana_combobox", conf.get("ana_combobox", default))
        conf.set("inv_ana_combobox", conf.get("inv_ana_combobox", default))

        def on_analyzer_check_toggled(check):
            self.widgets["analyzers_vbox"].set_sensitive(check.get_active())
            from pychess.widgets.gamewidget import widgets
            perspective = perspective_manager.get_perspective("games")
            if len(perspective.gamewidgets) != 0:
                if check.get_active():
                    for gmwidg in perspective.gamewidgets:
                        asyncio. async (
                            gmwidg.gamemodel.restart_analyzer(HINT))
                        if not widgets["hint_mode"].get_active():
                            gmwidg.gamemodel.pause_analyzer(HINT)
                else:
                    for gmwidg in perspective.gamewidgets:
                        gmwidg.gamemodel.remove_analyzer(HINT)

        self.widgets["analyzers_vbox"].set_sensitive(
            widgets["analyzer_check"].get_active())
        self.widgets["analyzer_check"].connect_after(
            "toggled", on_analyzer_check_toggled)

        def on_invanalyzer_check_toggled(check):
            self.widgets["inv_analyzers_vbox"].set_sensitive(
                check.get_active())
            perspective = perspective_manager.get_perspective("games")
            if len(perspective.gamewidgets) != 0:
                if check.get_active():
                    for gmwidg in perspective.gamewidgets:
                        asyncio. async (gmwidg.gamemodel.restart_analyzer(SPY))
                        if not widgets["spy_mode"].get_active():
                            gmwidg.gamemodel.pause_analyzer(SPY)
                else:
                    for gmwidg in perspective.gamewidgets:
                        gmwidg.gamemodel.remove_analyzer(SPY)

        self.widgets["inv_analyzers_vbox"].set_sensitive(
            widgets["inv_analyzer_check"].get_active())
        self.widgets["inv_analyzer_check"].connect_after(
            "toggled", on_invanalyzer_check_toggled)

        # Give widgets to keeper

        uistuff.keep(
            self.widgets["ana_combobox"], "ana_combobox", anal_combo_get_value,
            lambda combobox, value: anal_combo_set_value(
                combobox, value, "hint_mode", "analyzer_check", HINT))
        uistuff.keep(
            self.widgets["inv_ana_combobox"], "inv_ana_combobox",
            anal_combo_get_value, lambda combobox, value: anal_combo_set_value(
                combobox, value, "spy_mode", "inv_analyzer_check", SPY))

        uistuff.keep(self.widgets["max_analysis_spin"],
                     "max_analysis_spin",
                     first_value=3)
Beispiel #18
0
    def __init__(self, widgets):
        self.widgets = widgets
        self.dialog = self.widgets["manage_engines_dialog"]
        self.cur_engine = None
        self.default_workdir = getEngineDataPrefix()

        uistuff.keepWindowSize("engineswindow", self.dialog)

        # Put engines into tree store
        self.allstore = Gtk.ListStore(Pixbuf, str)

        self.tv = self.widgets["engines_treeview"]
        self.tv.set_model(self.allstore)
        self.tv.append_column(
            Gtk.TreeViewColumn("Flag", Gtk.CellRendererPixbuf(), pixbuf=0))
        name_renderer = Gtk.CellRendererText()
        name_renderer.set_property("editable", False)
        self.tv.append_column(Gtk.TreeViewColumn("Name", name_renderer,
                                                 text=1))

        # Add cell renderer to protocol combo column
        protocol_combo = self.widgets["engine_protocol_combo"]
        protocol_combo.set_name("engine_protocol_combo")
        cell = Gtk.CellRendererText()
        protocol_combo.pack_start(cell, True)
        protocol_combo.add_attribute(cell, "text", 0)

        # Add columns and cell renderers to options treeview
        self.options_store = Gtk.ListStore(str, str, GObject.TYPE_PYOBJECT)
        optv = self.widgets["options_treeview"]
        optv.set_model(self.options_store)
        optv.append_column(
            Gtk.TreeViewColumn("  ", Gtk.CellRendererText(), text=0))
        optv.append_column(
            Gtk.TreeViewColumn(_("Option"), Gtk.CellRendererText(), text=1))
        optv.append_column(
            Gtk.TreeViewColumn(_("Value"),
                               KeyValueCellRenderer(self.options_store),
                               data=2))

        self.update_store()

        def do_update_store(self, *args):
            GLib.idle_add(engine_dialog.update_store)

        discoverer.connect_after("engine_discovered", do_update_store)

        ################################################################
        # remove button
        ################################################################
        def remove(button):
            if self.cur_engine is not None:
                self.widgets['remove_engine_button'].set_sensitive(False)
                discoverer.removeEngine(self.cur_engine)

                selection = self.tv.get_selection()
                result = selection.get_selected()
                if result is not None:
                    model, ts_iter = result
                    model.remove(ts_iter)
                if model.iter_n_children() == 0:
                    clearView()

                # Notify playerCombos in NewGameTasker
                discoverer.emit("all_engines_discovered")

        self.widgets["remove_engine_button"].connect("clicked", remove)

        ################################################################
        # add button
        ################################################################
        engine_chooser_dialog = Gtk.FileChooserDialog(
            _("Select engine"), mainwindow(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        filter = Gtk.FileFilter()
        filter.set_name(_("Executable files"))
        filter.add_mime_type("application/x-executable")
        filter.add_mime_type("application/x-sharedlib")
        filter.add_mime_type("application/x-ms-dos-executable")
        filter.add_mime_type("application/x-msdownload")
        filter.add_pattern("*.exe")
        for vm in VM_LIST:
            filter.add_pattern("*%s" % vm.ext)

        engine_chooser_dialog.add_filter(filter)
        self.add = False

        def add(button):
            self.add = True
            response = engine_chooser_dialog.run()

            if response == Gtk.ResponseType.OK:
                new_engine = engine_chooser_dialog.get_filename()
                binname = os.path.split(new_engine)[1]
                ext = os.path.splitext(new_engine)[1]

                # Verify if the engine already exists under the same name
                if new_engine != "":
                    for eng in discoverer.getEngines():
                        if eng["command"] == new_engine:
                            msg_dia = Gtk.MessageDialog(
                                mainwindow(),
                                type=Gtk.MessageType.ERROR,
                                buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(
                                _("<big><b>Unable to add %s</b></big>" %
                                  new_engine))
                            msg_dia.format_secondary_text(
                                _("The engine is already installed under the same name"
                                  ))
                            msg_dia.run()
                            msg_dia.hide()
                            new_engine = ""
                            break

                # Detect the host application
                if new_engine != "":
                    vm_name = None
                    vm_args = None
                    vmpath = ""

                    # Scripting
                    for vm in VM_LIST:
                        if ext == vm.ext:
                            vm_name = vm.name
                            vm_args = vm.args
                            break

                    # Wine for Windows application under Linux
                    if vm_name is None and new_engine.lower().endswith(
                            ".exe") and sys.platform != "win32":
                        vm_name = "wine"

                    # Check that the interpreter is available
                    if vm_name is not None:
                        vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK)
                        if vmpath is None:
                            msg_dia = Gtk.MessageDialog(
                                mainwindow(),
                                type=Gtk.MessageType.ERROR,
                                buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(
                                _("<big><b>Unable to add %s</b></big>" %
                                  new_engine))
                            msg_dia.format_secondary_text(
                                vm_name + _(" is not installed"))
                            msg_dia.run()
                            msg_dia.hide()
                            new_engine = ""

                # Next checks
                if new_engine:
                    vm_ext_list = [vm.ext for vm in VM_LIST]
                    if ext not in vm_ext_list and not os.access(
                            new_engine, os.X_OK):
                        msg_dia = Gtk.MessageDialog(mainwindow(),
                                                    type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(
                            _("<big><b>%s is not marked executable in the filesystem</b></big>"
                              % new_engine))
                        msg_dia.format_secondary_text(
                            _("Try chmod a+x %s" % new_engine))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return

                    try:
                        engine_command = []
                        if vmpath:
                            engine_command.append(vmpath)
                        if vm_args is not None:
                            engine_command += vm_args
                        engine_command.append(new_engine)

                        # Search the engines based on the most expectable protocol
                        refeng = discoverer.getReferencedEngine(binname)
                        if refeng is not None and refeng[
                                "protocol"] == "xboard":
                            checkers = [is_cecp, is_uci]
                        else:
                            checkers = [is_uci, is_cecp]

                        uci = False
                        for checker in checkers:
                            check_ok = checker(engine_command)
                            if check_ok:
                                uci = checker is is_uci
                                break

                        if not check_ok:
                            # restore the original
                            engine = discoverer.getEngineByName(
                                self.cur_engine)
                            engine_chooser_dialog.set_filename(
                                engine["command"])
                            msg_dia = Gtk.MessageDialog(
                                mainwindow(),
                                type=Gtk.MessageType.ERROR,
                                buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(
                                _("<big><b>Unable to add %s</b></big>" %
                                  new_engine))
                            msg_dia.format_secondary_text(
                                _("There is something wrong with this executable"
                                  ))
                            msg_dia.run()
                            msg_dia.hide()
                            engine_chooser_dialog.hide()
                            self.add = False
                            engine_chooser_dialog.hide()
                            return

                        self.widgets["engine_command_entry"].set_text(
                            new_engine)
                        self.widgets["engine_protocol_combo"].set_active(
                            0 if uci else 1)
                        self.widgets["engine_args_entry"].set_text("")

                        # active = self.widgets["engine_protocol_combo"].get_active()
                        protocol = "uci" if uci else "xboard"

                        # print(binname, new_engine, protocol, vm_name, vm_args)
                        discoverer.addEngine(binname, new_engine, protocol,
                                             vm_name, vm_args)
                        self.cur_engine = binname
                        self.add = False
                        discoverer.discover()
                    except Exception:
                        msg_dia = Gtk.MessageDialog(mainwindow(),
                                                    type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(
                            _("<big><b>Unable to add %s</b></big>" %
                              new_engine))
                        msg_dia.format_secondary_text(
                            _("There is something wrong with this executable"))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return
                else:
                    # restore the original
                    engine = discoverer.getEngineByName(self.cur_engine)
                    engine_chooser_dialog.set_filename(engine["command"])

            engine_chooser_dialog.hide()

        self.widgets["add_engine_button"].connect("clicked", add)

        ################################################################
        # add in mass button
        ################################################################

        def addInMass(button):
            # Ask the user to select a folder
            folder_dlg = Gtk.FileChooserDialog(
                _("Choose a folder"), None,
                Gtk.FileChooserAction.SELECT_FOLDER,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
                 Gtk.ResponseType.OK))
            answer = folder_dlg.run()
            path = folder_dlg.get_filename()
            folder_dlg.destroy()

            # Search for the engines
            if answer != Gtk.ResponseType.OK:
                return False
            possibleFiles = listEnginesFromPath(path)

            # Remove the existing engines from the list
            def isNewEngine(path):
                sfn = os.path.basename(path)
                for engine in discoverer.getEngines():
                    if sfn in engine.get(
                            "command"):  # The short name must be unique
                        return False
                return True

            possibleFiles = [fn for fn in possibleFiles if isNewEngine(fn)]
            if len(possibleFiles) == 0:
                return False

            # Prepare the result in a dialog
            mass_dialog = self.widgets["engine_list_dialog"]
            self.widgets["mass_path_label"].set_text(path)
            mass_list = self.widgets["mass_list_treeview"]
            if len(mass_list.get_columns()) == 0:  # Not initialized yet
                mass_store = Gtk.ListStore(bool, str)
                mass_list.set_model(mass_store)

                def checkbox_renderer_cb(cell, path, model):
                    model[path][0] = not model[path][0]
                    return

                checkbox_renderer = Gtk.CellRendererToggle()
                checkbox_renderer.set_property("activatable", True)
                checkbox_renderer.connect("toggled", checkbox_renderer_cb,
                                          mass_store)
                mass_list.append_column(
                    Gtk.TreeViewColumn(_("Import"),
                                       checkbox_renderer,
                                       active=0))
                mass_list.append_column(
                    Gtk.TreeViewColumn(_("File name"),
                                       Gtk.CellRendererText(),
                                       text=1))
            else:
                mass_store = mass_list.get_model()

            mass_store.clear()
            for fn in possibleFiles:
                mass_store.append([False, fn[len(path):]])

            # Show the dialog
            answer = mass_dialog.run()
            mass_dialog.hide()
            if answer != Gtk.ResponseType.OK.real:
                return False

            # Add the new engines
            self.add = True
            found = False
            for entry in mass_store:
                if entry[0]:
                    newengine = discoverer.getReferencedEngine(path + entry[1])
                    if newengine is not None:
                        discoverer.addEngineFromReference(newengine)
                        found = True
            self.add = False
            if found:
                discoverer.discover()
            return True

        self.widgets["mass_engine_button"].connect("clicked", addInMass)

        ################################################################
        def clearView():
            self.selection = True
            self.cur_engine = None
            self.widgets["vm_command_entry"].set_text("")
            self.widgets["vm_args_entry"].set_text("")
            self.widgets["engine_command_entry"].set_text("")
            self.widgets["engine_args_entry"].set_text("")
            self.widgets["engine_protocol_combo"].set_active(0)
            self.widgets["engine_country_combo"].set_active(0)
            self.widgets["engine_comment_entry"].set_text("")
            self.widgets["engine_level_scale"].set_value(ENGINE_DEFAULT_LEVEL)
            self.options_store.clear()
            self.selection = False

        ################################################################
        # vm args
        ################################################################
        def vm_args_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_args = self.widgets["vm_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("vm_args")
                if new_args != old_args:
                    engine["vm_args"] = new_args.split()

        self.widgets["vm_args_entry"].connect("changed", vm_args_changed)

        ################################################################
        # engine args
        ################################################################
        def args_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_args = self.widgets["engine_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("args")
                if new_args != old_args:
                    engine["args"] = new_args.split()

        self.widgets["engine_args_entry"].connect("changed", args_changed)

        ################################################################
        # engine working directory
        ################################################################
        dir_chooser_dialog = Gtk.FileChooserDialog(
            _("Select working directory"), mainwindow(),
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        dir_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            dir_chooser_dialog)

        self.widgets["dirChooserDock"].add(dir_chooser_button)
        dir_chooser_button.show()

        def select_dir(button):
            new_directory = dir_chooser_dialog.get_filename()
            engine = discoverer.getEngineByName(self.cur_engine)
            old_directory = engine.get("workingDirectory")
            if new_directory != old_directory and new_directory != self.default_workdir:
                engine["workingDirectory"] = new_directory

        dir_chooser_button.connect("current-folder-changed", select_dir)

        ################################################################
        # engine protocol
        ################################################################
        def protocol_changed(widget):
            if self.cur_engine is not None and not self.add and not self.selection:
                active = self.widgets["engine_protocol_combo"].get_active()
                new_protocol = "uci" if active == 0 else "xboard"
                engine = discoverer.getEngineByName(self.cur_engine)
                old_protocol = engine["protocol"]
                if new_protocol != old_protocol:
                    command = engine.get("command")
                    engine_command = []
                    vm_command = engine.get("vm_command")
                    if vm_command is not None:
                        engine_command.append(vm_command)
                        vm_args = engine.get("vm_args")
                        if vm_args is not None:
                            engine_command.append(", ".join(vm_args))
                    engine_command.append(command)

                    # is the new protocol supported by the engine?
                    if new_protocol == "uci":
                        check_ok = is_uci(engine_command)
                    else:
                        check_ok = is_cecp(engine_command)

                    if check_ok:
                        # discover engine options for new protocol
                        engine["protocol"] = new_protocol
                        engine["recheck"] = True
                        discoverer.discover()
                    else:
                        # restore the original protocol
                        widgets["engine_protocol_combo"].set_active(
                            0 if old_protocol == "uci" else 1)

        self.widgets["engine_protocol_combo"].connect("changed",
                                                      protocol_changed)

        ################################################################
        # engine country
        ################################################################
        def country_changed(widget):
            if self.cur_engine is not None and not self.selection:
                engine = discoverer.getEngineByName(self.cur_engine)
                old_country = discoverer.getCountry(engine)
                new_country = ISO3166_LIST[widget.get_active()].iso2
                if old_country != new_country:
                    engine["country"] = new_country

                    # Refresh the flag in the tree view
                    path = addDataPrefix("flags/%s.png" % new_country)
                    if not os.path.isfile(path):
                        path = addDataPrefix("flags/unknown.png")
                    item = self.tv.get_selection().get_selected()
                    if item is not None:
                        model, ts_iter = item
                        model[ts_iter][0] = get_pixbuf(path)

                        # Notify playerCombos in NewGameTasker
                        discoverer.emit("all_engines_discovered")

        self.widgets["engine_country_combo"].connect("changed",
                                                     country_changed)

        def country_keypressed(widget, event):
            idx = 0
            for iso in ISO3166_LIST:
                if (idx != 0) and (
                    (ord(iso.country[0].lower()) == event.keyval) or
                    (ord(iso.country[0].upper()) == event.keyval)):
                    widget.set_active(idx)
                    break
                idx += 1

        self.widgets["engine_country_combo"].connect("key-press-event",
                                                     country_keypressed)

        ################################################################
        # comment changed
        ################################################################
        def comment_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_comment = self.widgets["engine_comment_entry"].get_text(
                ).strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_comment = engine.get("comment")
                if new_comment != old_comment:
                    engine["comment"] = new_comment

        self.widgets["engine_comment_entry"].connect("changed",
                                                     comment_changed)

        ################################################################
        # level changed
        ################################################################
        def level_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_level = widget.get_value()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_level = engine.get("level")
                if new_level != old_level:
                    engine["level"] = int(new_level)

        self.widgets["engine_level_scale"].connect("value-changed",
                                                   level_changed)

        ################################################################
        # engine tree
        ################################################################
        self.selection = False

        def selection_changed(treeselection):
            store, tv_iter = self.tv.get_selection().get_selected()
            if tv_iter:
                self.selection = True
                path = store.get_path(tv_iter)
                indices = path.get_indices()
                row = indices[0]
                name = store[row][1]
                self.cur_engine = name
                engine = discoverer.getEngineByName(name)
                if "PyChess.py" in engine["command"]:
                    self.widgets['remove_engine_button'].set_sensitive(False)
                else:
                    self.widgets['remove_engine_button'].set_sensitive(True)
                self.widgets["engine_command_entry"].set_text(
                    engine["command"])
                engine_chooser_dialog.set_filename(engine["command"])
                args = [] if engine.get("args") is None else engine.get("args")
                self.widgets["engine_args_entry"].set_text(' '.join(args))

                vm = engine.get("vm_command")
                self.widgets["vm_command_entry"].set_text(
                    vm if vm is not None else "")
                args = [] if engine.get("vm_args") is None else engine.get(
                    "vm_args")
                self.widgets["vm_args_entry"].set_text(' '.join(args))

                directory = engine.get("workingDirectory")
                dir_choice = directory if directory is not None else self.default_workdir
                dir_chooser_dialog.set_current_folder(dir_choice)
                self.widgets["engine_protocol_combo"].set_active(
                    0 if engine["protocol"] == "uci" else 1)

                self.widgets["engine_country_combo"].set_active(0)
                country = discoverer.getCountry(engine)
                idx = 0
                for iso in ISO3166_LIST:
                    if iso.iso2 == country:
                        self.widgets["engine_country_combo"].set_active(idx)
                        break
                    idx += 1

                comment = engine.get("comment")
                self.widgets["engine_comment_entry"].set_text(
                    comment if comment is not None else "")

                level = engine.get("level")
                try:
                    level = int(level)
                except Exception:
                    level = ENGINE_DEFAULT_LEVEL
                self.widgets["engine_level_scale"].set_value(level)

                self.update_options()
                self.selection = False

        tree_selection = self.tv.get_selection()
        tree_selection.connect('changed', selection_changed)
        tree_selection.select_path((0, ))
        selection_changed(tree_selection)

        ################################################################
        # restore the default options of the engine
        ################################################################

        def engine_default_options(button):
            if self.cur_engine is not None and not self.selection:
                engine = discoverer.getEngineByName(self.cur_engine)
                options = engine.get("options")
                if options:
                    dialog = Gtk.MessageDialog(mainwindow(),
                                               type=Gtk.MessageType.QUESTION,
                                               buttons=Gtk.ButtonsType.YES_NO)
                    dialog.set_markup(
                        _("Do you really want to restore the default options of the engine ?"
                          ))
                    response = dialog.run()
                    dialog.destroy()
                    if response == Gtk.ResponseType.YES:
                        for option in options:
                            if "default" in option:
                                option["value"] = option["default"]
                        self.update_options()

        self.widgets["engine_default_options_button"].connect(
            "clicked", engine_default_options)
Beispiel #19
0
    def __init__(self, widgets):
        self.widgets = widgets

        # Options on by default
        for key in ("opening_check", "endgame_check", "online_egtb_check",
                    "analyzer_check", "inv_analyzer_check"):
            uistuff.keep(widgets[key], key, first_value=True)

        # Opening book
        default_path = os.path.join(addDataPrefix("pychess_book.bin"))
        path = conf.get("opening_file_entry", default_path)
        conf.set("opening_file_entry", path)

        book_chooser_dialog = Gtk.FileChooserDialog(
            _("Select book file"), None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        book_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            book_chooser_dialog)

        filter = Gtk.FileFilter()
        filter.set_name(_("Opening books"))
        filter.add_pattern("*.bin")
        book_chooser_dialog.add_filter(filter)
        book_chooser_button.set_filename(path)

        self.widgets["bookChooserDock"].add(book_chooser_button)
        book_chooser_button.show()

        def select_new_book(button):
            new_book = book_chooser_dialog.get_filename()
            if new_book:
                conf.set("opening_file_entry", new_book)
            else:
                # restore the original
                book_chooser_dialog.set_filename(path)

        book_chooser_button.connect("file-set", select_new_book)

        def on_opening_check_toggled(check):
            self.widgets["opening_hbox"].set_sensitive(check.get_active())

        self.widgets["opening_check"].connect_after("toggled",
                                                    on_opening_check_toggled)

        # Endgame
        default_path = os.path.join(getDataPrefix())
        egtb_path = conf.get("egtb_path", default_path)
        conf.set("egtb_path", egtb_path)

        egtb_chooser_dialog = Gtk.FileChooserDialog(
            _("Select Gaviota TB path"), None,
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        egtb_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            egtb_chooser_dialog)
        egtb_chooser_button.set_current_folder(egtb_path)

        self.widgets["egtbChooserDock"].add(egtb_chooser_button)
        egtb_chooser_button.show()

        def select_egtb(button):
            new_directory = egtb_chooser_dialog.get_filename()
            if new_directory != egtb_path:
                conf.set("egtb_path", new_directory)

        egtb_chooser_button.connect("current-folder-changed", select_egtb)

        def on_endgame_check_toggled(check):
            self.widgets["endgame_hbox"].set_sensitive(check.get_active())

        self.widgets["endgame_check"].connect_after("toggled",
                                                    on_endgame_check_toggled)

        # Analyzing engines
        from pychess.widgets import newGameDialog
        data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
        uistuff.createCombo(widgets["ana_combobox"], data, name="ana_combobox")
        uistuff.createCombo(widgets["inv_ana_combobox"], data, name="inv_ana_combobox")

        def update_analyzers_store(discoverer):
            data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
            uistuff.updateCombo(widgets["ana_combobox"], data)
            uistuff.updateCombo(widgets["inv_ana_combobox"], data)

        discoverer.connect_after("all_engines_discovered",
                                 update_analyzers_store)
        update_analyzers_store(discoverer)

        # Save, load and make analyze combos active

        # Let Stockfish to be default analyzer in Windows installer
        default = discoverer.getEngineN(-1).get("md5")
        conf.set("ana_combobox", conf.get("ana_combobox", default))
        conf.set("inv_ana_combobox", conf.get("inv_ana_combobox", default))

        def on_analyzer_check_toggled(check):
            self.widgets["analyzers_vbox"].set_sensitive(check.get_active())
            from pychess.widgets.gamewidget import widgets
            perspective = perspective_manager.get_perspective("games")
            if len(perspective.gamewidgets) != 0:
                if check.get_active():
                    for gmwidg in perspective.gamewidgets:
                        asyncio.async(gmwidg.gamemodel.restart_analyzer(HINT))
                        if not widgets["hint_mode"].get_active():
                            gmwidg.gamemodel.pause_analyzer(HINT)
                else:
                    for gmwidg in perspective.gamewidgets:
                        gmwidg.gamemodel.remove_analyzer(HINT)

        self.widgets["analyzers_vbox"].set_sensitive(widgets[
            "analyzer_check"].get_active())
        self.widgets["analyzer_check"].connect_after("toggled",
                                                     on_analyzer_check_toggled)

        def on_invanalyzer_check_toggled(check):
            self.widgets["inv_analyzers_vbox"].set_sensitive(check.get_active())
            perspective = perspective_manager.get_perspective("games")
            if len(perspective.gamewidgets) != 0:
                if check.get_active():
                    for gmwidg in perspective.gamewidgets:
                        asyncio.async(gmwidg.gamemodel.restart_analyzer(SPY))
                        if not widgets["spy_mode"].get_active():
                            gmwidg.gamemodel.pause_analyzer(SPY)
                else:
                    for gmwidg in perspective.gamewidgets:
                        gmwidg.gamemodel.remove_analyzer(SPY)

        self.widgets["inv_analyzers_vbox"].set_sensitive(widgets[
            "inv_analyzer_check"].get_active())
        self.widgets["inv_analyzer_check"].connect_after(
            "toggled", on_invanalyzer_check_toggled)

        # Give widgets to keeper

        uistuff.keep(
            self.widgets["ana_combobox"], "ana_combobox", anal_combo_get_value,
            lambda combobox, value: anal_combo_set_value(combobox, value, "hint_mode", "analyzer_check", HINT))
        uistuff.keep(
            self.widgets["inv_ana_combobox"], "inv_ana_combobox",
            anal_combo_get_value,
            lambda combobox, value: anal_combo_set_value(combobox, value, "spy_mode", "inv_analyzer_check", SPY))

        uistuff.keep(self.widgets["max_analysis_spin"], "max_analysis_spin", first_value=3)
Beispiel #20
0
    def __init__(self, widgets):
        self.widgets = widgets
        self.dialog = self.widgets["manage_engines_dialog"]
        self.cur_engine = None
        self.default_workdir = getEngineDataPrefix()
        
        uistuff.keepWindowSize("engineswindow", self.dialog, defaultSize=(1, 500))

        # Put engines into tree store
        allstore = Gtk.ListStore(Pixbuf, str)
        
        self.tv = self.widgets["engines_treeview"]
        self.tv.set_model(allstore)
        self.tv.append_column(Gtk.TreeViewColumn(
                "Flag", Gtk.CellRendererPixbuf(), pixbuf=0))
        name_renderer = Gtk.CellRendererText()
        name_renderer.set_property("editable", True)
        self.tv.append_column(Gtk.TreeViewColumn("Name", name_renderer, text=1))
        def name_edited(renderer, path, new_name):
            if self.cur_engine is not None:
                old_name = self.cur_engine
                if new_name and new_name != old_name:
                    names = [engine["name"] for engine in discoverer.getEngines()]
                    if new_name not in names:
                        engine = discoverer.getEngineByName(self.cur_engine)
                        engine["name"] = new_name
                        discoverer.save()
                        self.cur_engine = new_name
                        update_store()                        
                        # Notify playerCombos in NewGameTasker
                        discoverer.emit("all_engines_discovered")
        name_renderer.connect("edited", name_edited)

        # Add cell renderer to protocol combo column
        protocol_combo = self.widgets["engine_protocol_combo"]
        cell = Gtk.CellRendererText()
        protocol_combo.pack_start(cell, True)
        protocol_combo.add_attribute(cell, "text", 0)

        # Add columns and cell renderers to options treeview 
        self.options_store = Gtk.ListStore(str, GObject.TYPE_PYOBJECT)
        optv = self.widgets["options_treeview"]
        optv.set_model(self.options_store)
        optv.append_column(Gtk.TreeViewColumn(
           "Option", Gtk.CellRendererText(), text=0))
        optv.append_column(Gtk.TreeViewColumn(
           "Data", KeyValueCellRenderer(self.options_store), data=1))

        def update_options(*args):
            if self.cur_engine is not None:
                engines = discoverer.getEngines()
                names = [engine["name"] for engine in engines]
                # After deleting an engine we will select first
                if self.cur_engine not in names:
                    self.cur_engine = engines[0]["name"]
                engine = discoverer.getEngineByName(self.cur_engine)
                options = engine.get("options")
                if options:
                    self.options_store.clear()
                    for option in options:
                        key = option["name"]
                        val = option
                        if option["type"] != "button":
                            val["default"] = option.get("default")
                            val["value"] = option.get("value", val["default"])
                        self.options_store.append([key, val])

        def update_store(*args):
            newGameDialog.createPlayerUIGlobals(discoverer)
            engine_names = [row[1] for row in allstore]
            new_items = []
            # don't add the very first (Human) player to engine store
            for item in newGameDialog.playerItems[0][1:]:
                if item[1] not in engine_names:
                    new_items.append(item)
            iter = None
            for item in new_items:
                iter = allstore.append(item)
            if iter is not None:
                ts = self.tv.get_selection()
                ts.select_iter(iter)
            update_options()

        update_store()

        def do_update_store(*args):
            GLib.idle_add(update_store)
        discoverer.connect_after("engine_discovered", do_update_store)
        
        ################################################################
        # remove button
        ################################################################
        def remove(button):
            if self.cur_engine is not None:
                self.widgets['remove_engine_button'].set_sensitive(False)
                engine = discoverer.getEngineByName(self.cur_engine)
                discoverer.removeEngine(self.cur_engine)
                discoverer.save()

                selection = self.tv.get_selection()
                result = selection.get_selected()
                if result is not None:
                    model, iter = result
                    model.remove(iter)

                # Notify playerCombos in NewGameTasker
                discoverer.emit("all_engines_discovered")

        self.widgets["remove_engine_button"].connect("clicked", remove)

        ################################################################
        # add button
        ################################################################
        engine_chooser_dialog = Gtk.FileChooserDialog(_("Select engine"), None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

        filter = Gtk.FileFilter()
        filter.set_name(_("Executable files"))
        filter.add_mime_type("application/x-executable")
        filter.add_mime_type("application/x-ms-dos-executable")
        filter.add_mime_type("application/x-msdownload")
        filter.add_pattern("*.exe")
        engine_chooser_dialog.add_filter(filter)
        self.add = False

        def add(button):
            self.add = True
            response = engine_chooser_dialog.run()

            if response == Gtk.ResponseType.OK:
                new_engine = engine_chooser_dialog.get_filename()
                if new_engine.lower().endswith(".exe") and sys.platform != "win32":
                    vm_name = "wine" 
                    vmpath = searchPath(vm_name, access=os.R_OK|os.X_OK)
                    if vmpath is None:
                        d = Gtk.MessageDialog(
                                type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
                        d.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                        d.format_secondary_text(_("wine not installed"))
                        d.run()
                        d.hide()
                        new_engine = ""
                    else:
                        vmpath += " "
                else:
                    vm_name = None
                    vmpath = ""
                
                if new_engine:
                    try:
                        # Some engines support CECP and UCI, but variant engines are CECP,
                        # so we better to start with CECP this case
                        variant_engines = ("fmax", "sjaakii", "sjeng")
                        if any((True for e in variant_engines if e in new_engine.lower())):
                            checkers = [is_cecp, is_uci]
                        else:
                            checkers = [is_uci, is_cecp]
                        uci = False
                        for checker in checkers:
                            ok = checker(vmpath + new_engine)
                            if ok:
                                uci = checker is is_uci
                                break
                            else:
                                continue
                            if not ok:
                                # restore the original
                                engine = discoverer.getEngineByName(self.cur_engine)
                                engine_chooser_dialog.set_filename(engine["command"])
                                d = Gtk.MessageDialog(
                                        type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
                                d.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                                d.format_secondary_text(_("There is something wrong with this executable"))
                                d.run()
                                d.hide()
                                engine_chooser_dialog.hide()
                                return
                        path, binname = os.path.split(new_engine)
                        for e in discoverer.getEngines():
                            if e["name"] == binname:
                                binname = e["name"] + "(1)"
                                break
                        self.widgets["engine_command_entry"].set_text(new_engine)
                        self.widgets["engine_protocol_combo"].set_active(0 if uci else 1)
                        self.widgets["engine_args_entry"].set_text("")
                        
                        active = self.widgets["engine_protocol_combo"].get_active()
                        protocol = "uci" if uci else "xboard"
                        
                        discoverer.addEngine(binname, new_engine, protocol, vm_name)
                        self.cur_engine = binname
                        self.add = False
                        discoverer.discover()
                    except:
                        d = Gtk.MessageDialog(
                                type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK)
                        d.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                        d.format_secondary_text(_("There is something wrong with this executable"))
                        d.run()
                        d.hide()
                else:
                    # restore the original
                    engine = discoverer.getEngineByName(self.cur_engine)
                    engine_chooser_dialog.set_filename(engine["command"])
            engine_chooser_dialog.hide()
            
        self.widgets["add_engine_button"].connect("clicked", add)


        ################################################################
        # engine args
        ################################################################
        def args_changed(widget):
            if self.cur_engine is not None:
                new_args = self.widgets["engine_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("args")
                if new_args != old_args:
                    engine["args"] = new_args.split()
                    discoverer.save()

        self.widgets["engine_args_entry"].connect("changed", args_changed)


        ################################################################
        # engine working directory
        ################################################################
        dir_chooser_dialog = Gtk.FileChooserDialog(_("Select working directory"), None, Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dir_chooser_button = Gtk.FileChooserButton.new_with_dialog(dir_chooser_dialog)

        self.widgets["dirChooserDock"].add(dir_chooser_button)
        dir_chooser_button.show()

        def select_dir(button):
            new_directory = dir_chooser_dialog.get_filename()
            engine = discoverer.getEngineByName(self.cur_engine)
            old_directory = engine.get("workingDirectory")
            if new_directory != old_directory and new_directory != self.default_workdir:
                engine["workingDirectory"] = new_directory
                discoverer.save()

        dir_chooser_button.connect("current-folder-changed", select_dir)


        ################################################################
        # engine protocol
        ################################################################
        def protocol_changed(widget):
            if self.cur_engine is not None and not self.add and not self.selection:
                active = self.widgets["engine_protocol_combo"].get_active()
                new_protocol = "uci" if active==0 else "xboard"
                engine = discoverer.getEngineByName(self.cur_engine)
                old_protocol = engine["protocol"]
                if new_protocol != old_protocol:
                    engine_command = engine_chooser_dialog.get_filename()
                    # is the new protocol supported by the engine?
                    if new_protocol == "uci":
                        ok = is_uci(engine_command)
                    else:
                        ok = is_cecp(engine_command)
                    if ok:
                        # discover engine options for new protocol
                        engine["protocol"] = new_protocol
                        engine["recheck"] = True
                        discoverer.discover()
                    else:
                        # restore the original protocol
                        widgets["engine_protocol_combo"].set_active(0 if old_protocol=="uci" else 1)

        self.widgets["engine_protocol_combo"].connect("changed", protocol_changed)


        ################################################################
        # engine tree
        ################################################################
        self.selection = False
        def selection_changed(treeselection):
            store, iter = self.tv.get_selection().get_selected()
            if iter:
                self.selection = True
                path = store.get_path(iter)
                indices = path.get_indices()
                row = indices[0]
                name = store[row][1]
                self.cur_engine = name
                engine = discoverer.getEngineByName(name)
                self.widgets['copy_engine_button'].set_sensitive(True)
                if "PyChess.py" in engine["command"]:
                    self.widgets['remove_engine_button'].set_sensitive(False)
                else:
                    self.widgets['remove_engine_button'].set_sensitive(True)
                self.widgets["engine_command_entry"].set_text(engine["command"])
                engine_chooser_dialog.set_filename(engine["command"])
                args = [] if engine.get("args") is None else engine.get("args")
                self.widgets["engine_args_entry"].set_text(' '.join(args))
                directory = engine.get("workingDirectory")
                d = directory if directory is not None else self.default_workdir
                dir_chooser_dialog.set_current_folder(d)
                self.widgets["engine_protocol_combo"].set_active(0 if engine["protocol"]=="uci" else 1)
                update_options()
                self.selection = False
                    
        tree_selection = self.tv.get_selection()
        tree_selection.connect('changed', selection_changed)
        tree_selection.select_path((0,))
Beispiel #21
0
    def __init__(self, widgets):
        self.widgets = widgets
        self.dialog = self.widgets["manage_engines_dialog"]
        self.cur_engine = None
        self.default_workdir = getEngineDataPrefix()

        uistuff.keepWindowSize("engineswindow", self.dialog)

        # Put engines into tree store
        self.allstore = Gtk.ListStore(Pixbuf, str)

        self.tv = self.widgets["engines_treeview"]
        self.tv.set_model(self.allstore)
        self.tv.append_column(Gtk.TreeViewColumn("Flag", Gtk.CellRendererPixbuf(), pixbuf=0))
        name_renderer = Gtk.CellRendererText()
        name_renderer.set_property("editable", False)
        self.tv.append_column(Gtk.TreeViewColumn("Name", name_renderer, text=1))

        # Add cell renderer to protocol combo column
        protocol_combo = self.widgets["engine_protocol_combo"]
        protocol_combo.set_name("engine_protocol_combo")
        cell = Gtk.CellRendererText()
        protocol_combo.pack_start(cell, True)
        protocol_combo.add_attribute(cell, "text", 0)

        # Add columns and cell renderers to options treeview
        self.options_store = Gtk.ListStore(str, str, GObject.TYPE_PYOBJECT)
        optv = self.widgets["options_treeview"]
        optv.set_model(self.options_store)
        optv.append_column(Gtk.TreeViewColumn("  ", Gtk.CellRendererText(), text=0))
        optv.append_column(Gtk.TreeViewColumn(_("Option"), Gtk.CellRendererText(), text=1))
        optv.append_column(Gtk.TreeViewColumn(_("Value"), KeyValueCellRenderer(self.options_store), data=2))

        self.update_store()

        def do_update_store(self, *args):
            GLib.idle_add(engine_dialog.update_store)

        discoverer.connect_after("engine_discovered", do_update_store)

        ################################################################
        # remove button
        ################################################################
        def remove(button):
            if self.cur_engine is not None:
                self.widgets['remove_engine_button'].set_sensitive(False)
                discoverer.removeEngine(self.cur_engine)

                selection = self.tv.get_selection()
                result = selection.get_selected()
                if result is not None:
                    model, ts_iter = result
                    model.remove(ts_iter)
                if model.iter_n_children() == 0:
                    clearView()

                # Notify playerCombos in NewGameTasker
                discoverer.emit("all_engines_discovered")

        self.widgets["remove_engine_button"].connect("clicked", remove)

        ################################################################
        # add button
        ################################################################
        engine_chooser_dialog = Gtk.FileChooserDialog(
            _("Select engine"), mainwindow(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        filter = Gtk.FileFilter()
        filter.set_name(_("Executable files"))
        filter.add_mime_type("application/x-executable")
        filter.add_mime_type("application/x-sharedlib")
        filter.add_mime_type("application/x-ms-dos-executable")
        filter.add_mime_type("application/x-msdownload")
        filter.add_pattern("*.exe")
        for vm in VM_LIST:
            filter.add_pattern("*%s" % vm.ext)

        engine_chooser_dialog.add_filter(filter)
        self.add = False

        def add(button):
            self.add = True
            response = engine_chooser_dialog.run()

            if response == Gtk.ResponseType.OK:
                new_engine = engine_chooser_dialog.get_filename()
                binname = os.path.split(new_engine)[1]
                ext = os.path.splitext(new_engine)[1]

                # Verify if the engine already exists under the same name
                if new_engine != "":
                    for eng in discoverer.getEngines():
                        if eng["command"] == new_engine:
                            msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                        buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                            msg_dia.format_secondary_text(_("The engine is already installed under the same name"))
                            msg_dia.run()
                            msg_dia.hide()
                            new_engine = ""
                            break

                # Detect the host application
                if new_engine != "":
                    vm_name = None
                    vm_args = None
                    vmpath = ""

                    # Scripting
                    for vm in VM_LIST:
                        if ext == vm.ext:
                            vm_name = vm.name
                            vm_args = vm.args
                            break

                    # Wine for Windows application under Linux
                    if vm_name is None and new_engine.lower().endswith(".exe") and sys.platform != "win32":
                        vm_name = "wine"

                    # Check that the interpreter is available
                    if vm_name is not None:
                        vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK)
                        if vmpath is None:
                            msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                        buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                            msg_dia.format_secondary_text(vm_name + _(" is not installed"))
                            msg_dia.run()
                            msg_dia.hide()
                            new_engine = ""

                # Next checks
                if new_engine:
                    vm_ext_list = [vm.ext for vm in VM_LIST]
                    if ext not in vm_ext_list and not os.access(new_engine, os.X_OK):
                        msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(_("<big><b>%s is not marked executable in the filesystem</b></big>" %
                                             new_engine))
                        msg_dia.format_secondary_text(_("Try chmod a+x %s" % new_engine))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return

                    try:
                        engine_command = []
                        if vmpath:
                            engine_command.append(vmpath)
                        if vm_args is not None:
                            engine_command.append(vm_args)
                        engine_command.append(new_engine)

                        # Search the engines based on the most expectable protocol
                        refeng = discoverer.getReferencedEngine(binname)
                        if refeng is not None and refeng["protocol"] == "xboard":
                            checkers = [is_cecp, is_uci]
                        else:
                            checkers = [is_uci, is_cecp]

                        uci = False
                        for checker in checkers:
                            check_ok = checker(engine_command)
                            if check_ok:
                                uci = checker is is_uci
                                break
                            else:
                                continue

                        if not check_ok:
                            # restore the original
                            engine = discoverer.getEngineByName(self.cur_engine)
                            engine_chooser_dialog.set_filename(engine["command"])
                            msg_dia = Gtk.MessageDialog(mainwindow(),
                                                        type=Gtk.MessageType.ERROR,
                                                        buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(
                                _("<big><b>Unable to add %s</b></big>" %
                                  new_engine))
                            msg_dia.format_secondary_text(_("There is something wrong with this executable"))
                            msg_dia.run()
                            msg_dia.hide()
                            engine_chooser_dialog.hide()
                            self.add = False
                            engine_chooser_dialog.hide()
                            return

                        self.widgets["engine_command_entry"].set_text(new_engine)
                        self.widgets["engine_protocol_combo"].set_active(0 if uci else 1)
                        self.widgets["engine_args_entry"].set_text("")

                        # active = self.widgets["engine_protocol_combo"].get_active()
                        protocol = "uci" if uci else "xboard"

                        if vm_args is not None:
                            vm_args = vm_args.split(",")
                        # print(binname, new_engine, protocol, vm_name, vm_args)
                        discoverer.addEngine(binname, new_engine, protocol, vm_name, vm_args)
                        self.cur_engine = binname
                        self.add = False
                        discoverer.discover()
                    except Exception:
                        msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(_("<big><b>Unable to add %s</b></big>" % new_engine))
                        msg_dia.format_secondary_text(_("There is something wrong with this executable"))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return
                else:
                    # restore the original
                    engine = discoverer.getEngineByName(self.cur_engine)
                    engine_chooser_dialog.set_filename(engine["command"])

            engine_chooser_dialog.hide()

        self.widgets["add_engine_button"].connect("clicked", add)

        ################################################################
        def clearView():
            self.selection = True
            self.cur_engine = None
            self.widgets["vm_command_entry"].set_text("")
            self.widgets["vm_args_entry"].set_text("")
            self.widgets["engine_command_entry"].set_text("")
            self.widgets["engine_args_entry"].set_text("")
            self.widgets["engine_protocol_combo"].set_active(0)
            self.widgets["engine_country_combo"].set_active(0)
            self.widgets["engine_comment_entry"].set_text("")
            self.widgets["engine_level_scale"].set_value(defaultEngineLevel)
            self.options_store.clear()
            self.selection = False

        ################################################################
        # vm args
        ################################################################
        def vm_args_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_args = self.widgets["vm_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("vm_args")
                if new_args != old_args:
                    engine["vm_args"] = new_args.split()

        self.widgets["vm_args_entry"].connect("changed", vm_args_changed)

        ################################################################
        # engine args
        ################################################################
        def args_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_args = self.widgets["engine_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("args")
                if new_args != old_args:
                    engine["args"] = new_args.split()

        self.widgets["engine_args_entry"].connect("changed", args_changed)

        ################################################################
        # engine working directory
        ################################################################
        dir_chooser_dialog = Gtk.FileChooserDialog(
            _("Select working directory"), mainwindow(),
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        dir_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            dir_chooser_dialog)

        self.widgets["dirChooserDock"].add(dir_chooser_button)
        dir_chooser_button.show()

        def select_dir(button):
            new_directory = dir_chooser_dialog.get_filename()
            engine = discoverer.getEngineByName(self.cur_engine)
            old_directory = engine.get("workingDirectory")
            if new_directory != old_directory and new_directory != self.default_workdir:
                engine["workingDirectory"] = new_directory

        dir_chooser_button.connect("current-folder-changed", select_dir)

        ################################################################
        # engine protocol
        ################################################################
        def protocol_changed(widget):
            if self.cur_engine is not None and not self.add and not self.selection:
                active = self.widgets["engine_protocol_combo"].get_active()
                new_protocol = "uci" if active == 0 else "xboard"
                engine = discoverer.getEngineByName(self.cur_engine)
                old_protocol = engine["protocol"]
                if new_protocol != old_protocol:
                    command = engine.get("command")
                    engine_command = []
                    vm_command = engine.get("vm_command")
                    if vm_command is not None:
                        engine_command.append(vm_command)
                        vm_args = engine.get("vm_args")
                        if vm_args is not None:
                            engine_command.append(", ".join(vm_args))
                    engine_command.append(command)

                    # is the new protocol supported by the engine?
                    if new_protocol == "uci":
                        check_ok = is_uci(engine_command)
                    else:
                        check_ok = is_cecp(engine_command)

                    if check_ok:
                        # discover engine options for new protocol
                        engine["protocol"] = new_protocol
                        engine["recheck"] = True
                        discoverer.discover()
                    else:
                        # restore the original protocol
                        widgets["engine_protocol_combo"].set_active(
                            0 if old_protocol == "uci" else 1)

        self.widgets["engine_protocol_combo"].connect("changed",
                                                      protocol_changed)

        ################################################################
        # engine country
        ################################################################
        def country_changed(widget):
            if self.cur_engine is not None and not self.selection:
                engine = discoverer.getEngineByName(self.cur_engine)
                old_country = discoverer.getCountry(engine)
                new_country = ISO3166_LIST[widget.get_active()].iso2
                if old_country != new_country:
                    engine["country"] = new_country

                    # Refresh the flag in the tree view
                    path = addDataPrefix("flags/%s.png" % new_country)
                    if not os.path.isfile(path):
                        path = addDataPrefix("flags/unknown.png")
                    item = self.tv.get_selection().get_selected()
                    if item is not None:
                        model, ts_iter = item
                        model[ts_iter][0] = get_pixbuf(path)

                        # Notify playerCombos in NewGameTasker
                        discoverer.emit("all_engines_discovered")

        self.widgets["engine_country_combo"].connect("changed", country_changed)

        def country_keypressed(widget, event):
            idx = 0
            for iso in ISO3166_LIST:
                if (idx != 0) and ((ord(iso.country[0].lower()) == event.keyval) or
                                   (ord(iso.country[0].upper()) == event.keyval)):
                    widget.set_active(idx)
                    break
                idx += 1

        self.widgets["engine_country_combo"].connect("key-press-event", country_keypressed)

        ################################################################
        # comment changed
        ################################################################
        def comment_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_comment = self.widgets["engine_comment_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_comment = engine.get("comment")
                if new_comment != old_comment:
                    engine["comment"] = new_comment

        self.widgets["engine_comment_entry"].connect("changed", comment_changed)

        ################################################################
        # level changed
        ################################################################
        def level_changed(widget):
            if self.cur_engine is not None and not self.selection:
                new_level = widget.get_value()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_level = engine.get("level")
                if new_level != old_level:
                    engine["level"] = int(new_level)

        self.widgets["engine_level_scale"].connect("value-changed", level_changed)

        ################################################################
        # engine tree
        ################################################################
        self.selection = False

        def selection_changed(treeselection):
            store, tv_iter = self.tv.get_selection().get_selected()
            if tv_iter:
                self.selection = True
                path = store.get_path(tv_iter)
                indices = path.get_indices()
                row = indices[0]
                name = store[row][1]
                self.cur_engine = name
                engine = discoverer.getEngineByName(name)
                if "PyChess.py" in engine["command"]:
                    self.widgets['remove_engine_button'].set_sensitive(False)
                else:
                    self.widgets['remove_engine_button'].set_sensitive(True)
                self.widgets["engine_command_entry"].set_text(engine["command"])
                engine_chooser_dialog.set_filename(engine["command"])
                args = [] if engine.get("args") is None else engine.get("args")
                self.widgets["engine_args_entry"].set_text(' '.join(args))

                vm = engine.get("vm_command")
                self.widgets["vm_command_entry"].set_text(vm if vm is not None else "")
                args = [] if engine.get("vm_args") is None else engine.get("vm_args")
                self.widgets["vm_args_entry"].set_text(' '.join(args))

                directory = engine.get("workingDirectory")
                dir_choice = directory if directory is not None else self.default_workdir
                dir_chooser_dialog.set_current_folder(dir_choice)
                self.widgets["engine_protocol_combo"].set_active(0 if engine["protocol"] == "uci" else 1)

                self.widgets["engine_country_combo"].set_active(0)
                country = discoverer.getCountry(engine)
                idx = 0
                for iso in ISO3166_LIST:
                    if iso.iso2 == country:
                        self.widgets["engine_country_combo"].set_active(idx)
                        break
                    idx += 1

                comment = engine.get("comment")
                self.widgets["engine_comment_entry"].set_text(comment if comment is not None else "")

                level = engine.get("level")
                try:
                    level = int(level) if level else defaultEngineLevel
                except Exception:
                    level = defaultEngineLevel
                self.widgets["engine_level_scale"].set_value(level)

                self.update_options()
                self.selection = False

        tree_selection = self.tv.get_selection()
        tree_selection.connect('changed', selection_changed)
        tree_selection.select_path((0, ))
        selection_changed(tree_selection)

        ################################################################
        # restore the default options of the engine
        ################################################################

        def engine_default_options(button):
            if self.cur_engine is not None and not self.selection:
                engine = discoverer.getEngineByName(self.cur_engine)
                options = engine.get("options")
                if options:
                    dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO)
                    dialog.set_markup(_("Do you really want to restore the default options of the engine ?"))
                    response = dialog.run()
                    dialog.destroy()
                    if response == Gtk.ResponseType.YES:
                        for option in options:
                            if "default" in option:
                                option["value"] = option["default"]
                        self.update_options()

        self.widgets["engine_default_options_button"].connect("clicked", engine_default_options)
def initialize(gameDic):

    uistuff.keep(widgets["fromCurrent"], "fromCurrent", first_value=True)
    uistuff.keep(widgets["threatPV"], "threatPV")
    uistuff.keep(widgets["showEval"], "showEval")
    uistuff.keep(widgets["showBlunder"], "showBlunder", first_value=True)
    uistuff.keep(widgets["max_analysis_spin"],
                 "max_analysis_spin",
                 first_value=3)
    uistuff.keep(widgets["variation_thresold_spin"],
                 "variation_thresold_spin",
                 first_value=50)

    # Analyzing engines
    uistuff.createCombo(widgets["ana_combobox"])

    from pychess.widgets import newGameDialog

    @idle_add
    def update_analyzers_store(discoverer):
        data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
        uistuff.updateCombo(widgets["ana_combobox"], data)

    discoverer.connect_after("all_engines_discovered", update_analyzers_store)
    update_analyzers_store(discoverer)

    uistuff.keep(
        widgets["ana_combobox"], "ana_combobox",
        anal_combo_get_value, lambda combobox, value: anal_combo_set_value(
            combobox, value, "hint_mode", "analyzer_check", HINT))

    def hide_window(button, *args):
        widgets["analyze_game"].hide()
        return True

    def abort():
        stop_event.set()
        widgets["analyze_game"].hide()

    def run_analyze(button, *args):
        gmwidg = gamewidget.cur_gmwidg()
        gamemodel = gameDic[gmwidg]

        old_check_value = conf.get("analyzer_check", True)
        conf.set("analyzer_check", True)
        analyzer = gamemodel.spectators[HINT]
        gmwidg.menuitems["hint_mode"].active = True
        threat_PV = conf.get("ThreatPV", False)
        if threat_PV:
            old_inv_check_value = conf.get("inv_analyzer_check", True)
            conf.set("inv_analyzer_check", True)
            inv_analyzer = gamemodel.spectators[SPY]
            gmwidg.menuitems["spy_mode"].active = True

        title = _("Game analyzing in progress...")
        text = _("Do you want to abort it?")
        content = InfoBar.get_message_content(title, text,
                                              Gtk.STOCK_DIALOG_QUESTION)

        def response_cb(infobar, response, message):
            message.dismiss()
            abort()

        message = InfoBarMessage(Gtk.MessageType.QUESTION, content,
                                 response_cb)
        message.add_button(
            InfoBarMessageButton(_("Abort"), Gtk.ResponseType.CANCEL))
        gmwidg.replaceMessages(message)

        def analyse_moves():
            from_current = conf.get("fromCurrent", True)
            start_ply = gmwidg.board.view.shown if from_current else 0
            move_time = int(conf.get("max_analysis_spin", 3))
            thresold = int(conf.get("variation_thresold_spin", 50))
            for board in gamemodel.boards[start_ply:]:
                if stop_event.is_set():
                    break

                @idle_add
                def do():
                    gmwidg.board.view.setShownBoard(board)

                do()
                analyzer.setBoard(board)
                if threat_PV:
                    inv_analyzer.setBoard(board)
                time.sleep(move_time + 0.1)

                ply = board.ply
                if ply - 1 in gamemodel.scores and ply in gamemodel.scores:
                    color = (ply - 1) % 2
                    oldmoves, oldscore, olddepth = gamemodel.scores[ply - 1]
                    score_str = prettyPrintScore(oldscore, olddepth)
                    oldscore = oldscore * -1 if color == BLACK else oldscore
                    moves, score, depth = gamemodel.scores[ply]
                    score = score * -1 if color == WHITE else score
                    diff = score - oldscore
                    if (diff > thresold
                            and color == BLACK) or (diff < -1 * thresold
                                                    and color == WHITE):
                        if threat_PV:
                            try:
                                if ply - 1 in gamemodel.spy_scores:
                                    oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[
                                        ply - 1]
                                    score_str0 = prettyPrintScore(
                                        oldscore0, olddepth0)
                                    pv0 = listToMoves(gamemodel.boards[ply -
                                                                       1],
                                                      ["--"] + oldmoves0,
                                                      validate=True)
                                    if len(pv0) > 2:
                                        gamemodel.add_variation(
                                            gamemodel.boards[ply - 1],
                                            pv0,
                                            comment="Treatening",
                                            score=score_str0)
                            except ParsingError as e:
                                # ParsingErrors may happen when parsing "old" lines from
                                # analyzing engines, which haven't yet noticed their new tasks
                                log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % \
                                    (' '.join(oldmoves),e))
                        try:
                            pv = listToMoves(gamemodel.boards[ply - 1],
                                             oldmoves,
                                             validate=True)
                            gamemodel.add_variation(gamemodel.boards[ply - 1],
                                                    pv,
                                                    comment="Better is",
                                                    score=score_str)
                        except ParsingError as e:
                            # ParsingErrors may happen when parsing "old" lines from
                            # analyzing engines, which haven't yet noticed their new tasks
                            log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % \
                                (' '.join(oldmoves),e))

            widgets["analyze_game"].hide()
            widgets["analyze_ok_button"].set_sensitive(True)
            conf.set("analyzer_check", old_check_value)
            if threat_PV:
                conf.set("inv_analyzer_check", old_inv_check_value)
            message.dismiss()

        t = threading.Thread(target=analyse_moves, name=fident(analyse_moves))
        t.daemon = True
        t.start()
        hide_window(None)

        return True

    widgets["analyze_game"].connect("delete-event", hide_window)
    widgets["analyze_cancel_button"].connect("clicked", hide_window)
    widgets["analyze_ok_button"].connect("clicked", run_analyze)
Beispiel #23
0
    def __init__(self, widgets):
        self.widgets = widgets
        self.dialog = self.widgets["manage_engines_dialog"]
        self.cur_engine = None
        self.default_workdir = getEngineDataPrefix()

        uistuff.keepWindowSize("engineswindow", self.dialog)

        # Put engines into tree store
        allstore = Gtk.ListStore(Pixbuf, str)

        self.tv = self.widgets["engines_treeview"]
        self.tv.set_model(allstore)
        self.tv.append_column(Gtk.TreeViewColumn("Flag",
                                                 Gtk.CellRendererPixbuf(),
                                                 pixbuf=0))
        name_renderer = Gtk.CellRendererText()
        name_renderer.set_property("editable", False)
        self.tv.append_column(Gtk.TreeViewColumn("Name",
                                                 name_renderer,
                                                 text=1))

        def name_edited(renderer, path, new_name):
            if self.cur_engine is not None:
                old_name = self.cur_engine
                if new_name and new_name != old_name:
                    names = [engine["name"]
                             for engine in discoverer.getEngines()]
                    if new_name not in names:
                        engine = discoverer.getEngineByName(self.cur_engine)
                        engine["name"] = new_name
                        discoverer.save()
                        self.cur_engine = new_name
                        update_store()
                        # Notify playerCombos in NewGameTasker
                        discoverer.emit("all_engines_discovered")

        name_renderer.connect("edited", name_edited)

        # Add cell renderer to protocol combo column
        protocol_combo = self.widgets["engine_protocol_combo"]
        protocol_combo.set_name("engine_protocol_combo")
        cell = Gtk.CellRendererText()
        protocol_combo.pack_start(cell, True)
        protocol_combo.add_attribute(cell, "text", 0)

        # Add columns and cell renderers to options treeview
        self.options_store = Gtk.ListStore(str, GObject.TYPE_PYOBJECT)
        optv = self.widgets["options_treeview"]
        optv.set_model(self.options_store)
        optv.append_column(Gtk.TreeViewColumn("Option",
                                              Gtk.CellRendererText(),
                                              text=0))
        optv.append_column(Gtk.TreeViewColumn("Data",
                                              KeyValueCellRenderer(
                                                  self.options_store),
                                              data=1))

        def update_options(*args):
            if self.cur_engine is not None:
                engines = discoverer.getEngines()
                names = [engine["name"] for engine in engines]
                # After deleting an engine we will select first
                if self.cur_engine not in names:
                    self.cur_engine = engines[0]["name"]
                engine = discoverer.getEngineByName(self.cur_engine)
                options = engine.get("options")
                self.options_store.clear()
                if options:
                    options.sort(key=lambda obj: obj['name'].lower() if 'name' in obj else '')
                    for option in options:
                        key = option["name"]
                        val = option
                        if option["type"] != "button":
                            val["default"] = option.get("default")
                            val["value"] = option.get("value", val["default"])
                        self.options_store.append([key, val])

        def update_store(*args):
            newGameDialog.createPlayerUIGlobals(discoverer)
            engine_names = [row[1] for row in allstore]
            new_items = []
            # don't add the very first (Human) player to engine store
            for item in newGameDialog.allEngineItems:
                if item[1] not in engine_names:
                    new_items.append(item)
            ts_iter = None
            for item in new_items:
                ts_iter = allstore.append(item)
            if ts_iter is not None:
                text_select = self.tv.get_selection()
                text_select.select_iter(ts_iter)
            update_options()

        update_store()

        def do_update_store(*args):
            GLib.idle_add(update_store)

        discoverer.connect_after("engine_discovered", do_update_store)

        ################################################################
        # remove button
        ################################################################
        def remove(button):
            if self.cur_engine is not None:
                self.widgets['remove_engine_button'].set_sensitive(False)
                # engine = discoverer.getEngineByName(self.cur_engine)
                discoverer.removeEngine(self.cur_engine)
                discoverer.save()

                selection = self.tv.get_selection()
                result = selection.get_selected()
                if result is not None:
                    model, ts_iter = result
                    model.remove(ts_iter)

                # Notify playerCombos in NewGameTasker
                discoverer.emit("all_engines_discovered")

        self.widgets["remove_engine_button"].connect("clicked", remove)

        ################################################################
        # add button
        ################################################################
        engine_chooser_dialog = Gtk.FileChooserDialog(
            _("Select engine"), mainwindow(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        filter = Gtk.FileFilter()
        filter.set_name(_("Executable files"))
        filter.add_mime_type("application/x-executable")
        filter.add_mime_type("application/x-sharedlib")
        filter.add_mime_type("application/x-ms-dos-executable")
        filter.add_mime_type("application/x-msdownload")
        filter.add_pattern("*.exe")
        for vm in VM_LIST:
            filter.add_pattern("*%s" % vm.ext)

        engine_chooser_dialog.add_filter(filter)
        self.add = False

        def add(button):
            self.add = True
            response = engine_chooser_dialog.run()

            if response == Gtk.ResponseType.OK:
                new_engine = engine_chooser_dialog.get_filename()
                vm_name = None
                vm_args = None
                vmpath = ""
                if new_engine.lower().endswith(".exe") and sys.platform != "win32":
                    vm_name = "wine"
                    vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK)
                    if vmpath is None:
                        msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(_("<big><b>Unable to add %s</b></big>" %
                                             new_engine))
                        msg_dia.format_secondary_text(_("wine not installed"))
                        msg_dia.run()
                        msg_dia.hide()
                        new_engine = ""

                for vm in VM_LIST:
                    ext = os.path.splitext(new_engine)[1]
                    if ext == vm.ext:
                        vm_name = vm.name
                        vm_args = vm.args
                        vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK)
                        if vmpath is None:
                            msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                        buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(_("<big><b>Unable to add %s</b></big>" %
                                                 new_engine))
                            msg_dia.format_secondary_text(vm_name + _(" is not installed"))
                            msg_dia.run()
                            msg_dia.hide()
                            new_engine = ""
                        break

                if new_engine:
                    vm_ext_list = [vm.ext for vm in VM_LIST]
                    if ext not in vm_ext_list and not os.access(new_engine, os.X_OK):
                        msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(_("<big><b>%s is not marked executable in the filesystem</b></big>" %
                                             new_engine))
                        msg_dia.format_secondary_text(_("Try chmod a+x %s" % new_engine))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return

                    try:
                        engine_command = []
                        if vmpath:
                            engine_command.append(vmpath)
                        if vm_args is not None:
                            engine_command.append(vm_args)
                        engine_command.append(new_engine)
                        # Some engines support CECP and UCI, but main variant engines are CECP,
                        # so we better to start with CECP this case
                        variant_engines = ("fmax", "sjaakii", "sjeng")
                        if any((True
                                for eng in variant_engines
                                if eng in new_engine.lower())):
                            checkers = [is_cecp, is_uci]
                        else:
                            checkers = [is_uci, is_cecp]

                        uci = False
                        for checker in checkers:
                            check_ok = checker(engine_command)
                            if check_ok:
                                uci = checker is is_uci
                                break
                            else:
                                continue

                        if not check_ok:
                            # restore the original
                            engine = discoverer.getEngineByName(
                                self.cur_engine)
                            engine_chooser_dialog.set_filename(engine[
                                "command"])
                            msg_dia = Gtk.MessageDialog(mainwindow(),
                                                        type=Gtk.MessageType.ERROR,
                                                        buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(
                                _("<big><b>Unable to add %s</b></big>" %
                                  new_engine))
                            msg_dia.format_secondary_text(_(
                                "There is something wrong with this executable"))
                            msg_dia.run()
                            msg_dia.hide()
                            engine_chooser_dialog.hide()
                            self.add = False
                            engine_chooser_dialog.hide()
                            return

                        binname = os.path.split(new_engine)[1]
                        for eng in discoverer.getEngines():
                            if eng["name"] == binname:
                                binname = eng["name"] + "(1)"
                                break

                        self.widgets["engine_command_entry"].set_text(new_engine)
                        self.widgets["engine_protocol_combo"].set_active(0 if uci else 1)
                        self.widgets["engine_args_entry"].set_text("")

                        # active = self.widgets["engine_protocol_combo"].get_active()
                        protocol = "uci" if uci else "xboard"

                        if vm_args is not None:
                            vm_args = vm_args.split(",")
                        # print(binname, new_engine, protocol, vm_name, vm_args)
                        discoverer.addEngine(binname, new_engine, protocol, vm_name, vm_args, "unknown")
                        self.cur_engine = binname
                        self.add = False
                        discoverer.discover()
                    except Exception:
                        msg_dia = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(_("<big><b>Unable to add %s</b></big>" %
                                             new_engine))
                        msg_dia.format_secondary_text(_(
                            "There is something wrong with this executable"))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return
                else:
                    # restore the original
                    engine = discoverer.getEngineByName(self.cur_engine)
                    engine_chooser_dialog.set_filename(engine["command"])

            engine_chooser_dialog.hide()

        self.widgets["add_engine_button"].connect("clicked", add)

        ################################################################
        # vm args
        ################################################################
        def vm_args_changed(widget):
            if self.cur_engine is not None:
                new_args = self.widgets["vm_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("vm_args")
                if new_args != old_args:
                    engine["vm_args"] = new_args.split()
                    discoverer.save()

        self.widgets["vm_args_entry"].connect("changed", vm_args_changed)

        ################################################################
        # engine args
        ################################################################
        def args_changed(widget):
            if self.cur_engine is not None:
                new_args = self.widgets["engine_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("args")
                if new_args != old_args:
                    engine["args"] = new_args.split()
                    discoverer.save()

        self.widgets["engine_args_entry"].connect("changed", args_changed)

        ################################################################
        # engine working directory
        ################################################################
        dir_chooser_dialog = Gtk.FileChooserDialog(
            _("Select working directory"), mainwindow(),
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        dir_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            dir_chooser_dialog)

        self.widgets["dirChooserDock"].add(dir_chooser_button)
        dir_chooser_button.show()

        def select_dir(button):
            new_directory = dir_chooser_dialog.get_filename()
            engine = discoverer.getEngineByName(self.cur_engine)
            old_directory = engine.get("workingDirectory")
            if new_directory != old_directory and new_directory != self.default_workdir:
                engine["workingDirectory"] = new_directory
                discoverer.save()

        dir_chooser_button.connect("current-folder-changed", select_dir)

        ################################################################
        # engine protocol
        ################################################################
        def protocol_changed(widget):
            if self.cur_engine is not None and not self.add and not self.selection:
                active = self.widgets["engine_protocol_combo"].get_active()
                new_protocol = "uci" if active == 0 else "xboard"
                engine = discoverer.getEngineByName(self.cur_engine)
                old_protocol = engine["protocol"]
                if new_protocol != old_protocol:
                    command = engine.get("command")
                    engine_command = []
                    vm_command = engine.get("vm_command")
                    if vm_command is not None:
                        engine_command.append(vm_command)
                        vm_args = engine.get("vm_args")
                        if vm_args is not None:
                            engine_command.append(", ".join(vm_args))
                    engine_command.append(command)

                    # is the new protocol supported by the engine?
                    if new_protocol == "uci":
                        check_ok = is_uci(engine_command)
                    else:
                        check_ok = is_cecp(engine_command)

                    if check_ok:
                        # discover engine options for new protocol
                        engine["protocol"] = new_protocol
                        engine["recheck"] = True
                        discoverer.discover()
                    else:
                        # restore the original protocol
                        widgets["engine_protocol_combo"].set_active(
                            0 if old_protocol == "uci" else 1)

        self.widgets["engine_protocol_combo"].connect("changed",
                                                      protocol_changed)

        ################################################################
        # engine country
        ################################################################
        def country_changed(widget):
            if self.cur_engine is not None and not self.selection:
                engine = discoverer.getEngineByName(self.cur_engine)
                old_country = discoverer.getCountry(engine)
                new_country = ISO3166_LIST[widget.get_active()].iso2
                if old_country != new_country:
                    engine["country"] = new_country
                    discoverer.save()

                    # Refresh the flag in the tree view
                    path = addDataPrefix("flags/%s.png" % new_country)
                    if not os.path.isfile(path):
                        path = addDataPrefix("flags/unknown.png")
                    item = self.tv.get_selection().get_selected()
                    if item is not None:
                        model, ts_iter = item
                        model[ts_iter][0] = get_pixbuf(path)

                        # Notify playerCombos in NewGameTasker
                        discoverer.emit("all_engines_discovered")

        self.widgets["engine_country_combo"].connect("changed", country_changed)

        def country_keypressed(widget, event):
            idx = 0
            for iso in ISO3166_LIST:
                if (idx != 0) and ((ord(iso.country[0].lower()) == event.keyval) or
                                   (ord(iso.country[0].upper()) == event.keyval)):
                    widget.set_active(idx)
                    break
                idx += 1

        self.widgets["engine_country_combo"].connect("key-press-event", country_keypressed)

        ################################################################
        # engine tree
        ################################################################
        self.selection = False

        def selection_changed(treeselection):
            store, tv_iter = self.tv.get_selection().get_selected()
            if tv_iter:
                self.selection = True
                path = store.get_path(tv_iter)
                indices = path.get_indices()
                row = indices[0]
                name = store[row][1]
                self.cur_engine = name
                engine = discoverer.getEngineByName(name)
                self.widgets['copy_engine_button'].set_sensitive(True)
                if "PyChess.py" in engine["command"]:
                    self.widgets['remove_engine_button'].set_sensitive(False)
                else:
                    self.widgets['remove_engine_button'].set_sensitive(True)
                self.widgets["engine_command_entry"].set_text(engine["command"])
                engine_chooser_dialog.set_filename(engine["command"])
                args = [] if engine.get("args") is None else engine.get("args")
                self.widgets["engine_args_entry"].set_text(' '.join(args))

                vm = engine.get("vm_command")
                self.widgets["vm_command_entry"].set_text(vm if vm is not None else "")
                args = [] if engine.get("vm_args") is None else engine.get("vm_args")
                self.widgets["vm_args_entry"].set_text(' '.join(args))

                directory = engine.get("workingDirectory")
                dir_choice = directory if directory is not None else self.default_workdir
                dir_chooser_dialog.set_current_folder(dir_choice)
                self.widgets["engine_protocol_combo"].set_active(0 if engine["protocol"] == "uci" else 1)

                self.widgets["engine_country_combo"].set_active(0)
                country = discoverer.getCountry(engine)
                idx = 0
                for iso in ISO3166_LIST:
                    if iso.iso2 == country:
                        self.widgets["engine_country_combo"].set_active(idx)
                        break
                    idx += 1

                update_options()
                self.selection = False

        tree_selection = self.tv.get_selection()
        tree_selection.connect('changed', selection_changed)
        tree_selection.select_path((0, ))
        selection_changed(tree_selection)

        ################################################################
        # restore the default options of the engine
        ################################################################

        def engine_default_options(button):
            if self.cur_engine is not None and not self.selection:
                engine = discoverer.getEngineByName(self.cur_engine)
                options = engine.get("options")
                if options:
                    dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO)
                    dialog.set_markup(_("Do you really want to restore the default options of the engine ?"))
                    response = dialog.run()
                    dialog.destroy()
                    if response == Gtk.ResponseType.YES:
                        for option in options:
                            if "default" in option:
                                option["value"] = option["default"]
                        discoverer.save()
                        update_options()

        self.widgets["engine_default_options_button"].connect("clicked", engine_default_options)
Beispiel #24
0
    def _init(cls):
        cls.white = get_pixbuf("glade/white.png")
        cls.black = get_pixbuf("glade/black.png")

        cls.widgets = uistuff.GladeWidgets("newInOut.glade")
        cls.widgets["newgamedialog"].set_transient_for(mainwindow())

        def on_exchange_players(widget, button_event):
            white = cls.widgets["whitePlayerCombobox"].get_active()
            black = cls.widgets["blackPlayerCombobox"].get_active()
            whiteLevel = cls.widgets["skillSlider1"].get_value()
            blackLevel = cls.widgets["skillSlider2"].get_value()
            cls.widgets["whitePlayerCombobox"].set_active(black)
            cls.widgets["blackPlayerCombobox"].set_active(white)
            cls.widgets["skillSlider1"].set_value(blackLevel)
            cls.widgets["skillSlider2"].set_value(whiteLevel)

        cls.widgets["whitePlayerButton"].set_image(Gtk.Image.new_from_pixbuf(cls.white))
        cls.widgets["whitePlayerButton"].connect("button-press-event", on_exchange_players)
        cls.widgets["blackPlayerButton"].set_image(Gtk.Image.new_from_pixbuf(cls.black))
        cls.widgets["blackPlayerButton"].connect("button-press-event", on_exchange_players)

        uistuff.createCombo(cls.widgets["whitePlayerCombobox"], name="whitePlayerCombobox")
        uistuff.createCombo(cls.widgets["blackPlayerCombobox"], name="blackPlayerCombobox")

        cls.widgets["playersIcon"].set_from_pixbuf(big_people)
        cls.widgets["timeIcon"].set_from_pixbuf(big_time)

        def on_playerCombobox_changed(widget, skill_hbox, skill_level):
            position = widget.get_active()
            skill_hbox.props.visible = position > 0
            if position > 0:
                tree_iter = widget.get_active_iter()
                if tree_iter is not None:
                    engine_name = widget.get_model()[tree_iter][1]
                    engine = discoverer.getEngineByName(engine_name)
                    if engine:
                        pref_level = engine.get("level")
                        if pref_level:
                            skill_level.set_value(pref_level)

        cls.widgets["whitePlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox1"], cls.widgets["skillSlider1"])
        cls.widgets["blackPlayerCombobox"].connect("changed", on_playerCombobox_changed, cls.widgets["skillHbox2"], cls.widgets["skillSlider2"])
        cls.widgets["whitePlayerCombobox"].set_active(0)
        cls.widgets["blackPlayerCombobox"].set_active(1)

        def on_skill_changed(scale, image):
            image.set_from_pixbuf(skillToIcon[int(scale.get_value())])

        cls.widgets["skillSlider1"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon1"])
        cls.widgets["skillSlider2"].connect("value-changed", on_skill_changed, cls.widgets["skillIcon2"])
        cls.widgets["skillSlider1"].set_value(3)
        cls.widgets["skillSlider2"].set_value(3)

        cls.__initTimeRadio("ngblitz", cls.widgets["blitzRadio"], cls.widgets["configImageBlitz"], 5, 0, 0)
        cls.__initTimeRadio("ngrapid", cls.widgets["rapidRadio"], cls.widgets["configImageRapid"], 15, 5, 0)
        cls.__initTimeRadio("ngnormal", cls.widgets["normalRadio"], cls.widgets["configImageNormal"], 45, 15, 0)
        cls.__initTimeRadio("ngclassical", cls.widgets["classicalRadio"], cls.widgets["configImageClassical"], 3, 0, 40)

        cls.__initVariantRadio("ngvariant1", cls.widgets["playVariant1Radio"], cls.widgets["configImageVariant1"])
        cls.__initVariantRadio("ngvariant2", cls.widgets["playVariant2Radio"], cls.widgets["configImageVariant2"])

        def updateCombos(*args):
            if cls.widgets["playNormalRadio"].get_active():
                variant = NORMALCHESS
            elif cls.widgets["playVariant1Radio"].get_active():
                variant = conf.get("ngvariant1")
            else:
                variant = conf.get("ngvariant2")
            variant1 = conf.get("ngvariant1")
            cls.widgets["playVariant1Radio"].set_tooltip_text(variants[variant1].__desc__)
            variant2 = conf.get("ngvariant2")
            cls.widgets["playVariant2Radio"].set_tooltip_text(variants[variant2].__desc__)
            data = [(item[0], item[1]) for item in playerItems[variant]]
            uistuff.updateCombo(cls.widgets["blackPlayerCombobox"], data)
            uistuff.updateCombo(cls.widgets["whitePlayerCombobox"], data)

        discoverer.connect_after("all_engines_discovered", updateCombos)
        updateCombos(discoverer)

        conf.notify_add("ngvariant1", updateCombos)
        conf.notify_add("ngvariant2", updateCombos)
        cls.widgets["playNormalRadio"].connect("toggled", updateCombos)
        cls.widgets["playNormalRadio"].set_tooltip_text(variants[NORMALCHESS].__desc__)
        cls.widgets["playVariant1Radio"].connect("toggled", updateCombos)
        variant1 = conf.get("ngvariant1")
        cls.widgets["playVariant1Radio"].set_tooltip_text(variants[variant1].__desc__)
        cls.widgets["playVariant2Radio"].connect("toggled", updateCombos)
        variant2 = conf.get("ngvariant2")
        cls.widgets["playVariant2Radio"].set_tooltip_text(variants[variant2].__desc__)

        # The "variant" has to come before players, because the engine positions
        # in the user comboboxes can be different in different variants
        for key in ("whitePlayerCombobox", "blackPlayerCombobox",
                    "skillSlider1", "skillSlider2", "notimeRadio",
                    "blitzRadio", "rapidRadio", "normalRadio", "classicalRadio",
                    "playNormalRadio", "playVariant1Radio", "playVariant2Radio"):
            uistuff.keep(cls.widgets[key], key)

        # We don't want the dialog to deallocate when closed. Rather we hide
        # it on respond
        cls.widgets["newgamedialog"].connect("delete_event", lambda *a: True)
Beispiel #25
0
    def __init__(self, widgets):
        self.widgets = widgets
        self.dialog = self.widgets["manage_engines_dialog"]
        self.cur_engine = None
        self.default_workdir = getEngineDataPrefix()

        uistuff.keepWindowSize("engineswindow",
                               self.dialog,
                               defaultSize=(1, 500))

        # Put engines into tree store
        allstore = Gtk.ListStore(Pixbuf, str)

        self.tv = self.widgets["engines_treeview"]
        self.tv.set_model(allstore)
        self.tv.append_column(
            Gtk.TreeViewColumn("Flag", Gtk.CellRendererPixbuf(), pixbuf=0))
        name_renderer = Gtk.CellRendererText()
        name_renderer.set_property("editable", True)
        self.tv.append_column(Gtk.TreeViewColumn("Name", name_renderer,
                                                 text=1))

        def name_edited(renderer, path, new_name):
            if self.cur_engine is not None:
                old_name = self.cur_engine
                if new_name and new_name != old_name:
                    names = [
                        engine["name"] for engine in discoverer.getEngines()
                    ]
                    if new_name not in names:
                        engine = discoverer.getEngineByName(self.cur_engine)
                        engine["name"] = new_name
                        discoverer.save()
                        self.cur_engine = new_name
                        update_store()
                        # Notify playerCombos in NewGameTasker
                        discoverer.emit("all_engines_discovered")

        name_renderer.connect("edited", name_edited)

        # Add cell renderer to protocol combo column
        protocol_combo = self.widgets["engine_protocol_combo"]
        protocol_combo.set_name("engine_protocol_combo")
        cell = Gtk.CellRendererText()
        protocol_combo.pack_start(cell, True)
        protocol_combo.add_attribute(cell, "text", 0)

        # Add columns and cell renderers to options treeview
        self.options_store = Gtk.ListStore(str, GObject.TYPE_PYOBJECT)
        optv = self.widgets["options_treeview"]
        optv.set_model(self.options_store)
        optv.append_column(
            Gtk.TreeViewColumn("Option", Gtk.CellRendererText(), text=0))
        optv.append_column(
            Gtk.TreeViewColumn("Data",
                               KeyValueCellRenderer(self.options_store),
                               data=1))

        def update_options(*args):
            if self.cur_engine is not None:
                engines = discoverer.getEngines()
                names = [engine["name"] for engine in engines]
                # After deleting an engine we will select first
                if self.cur_engine not in names:
                    self.cur_engine = engines[0]["name"]
                engine = discoverer.getEngineByName(self.cur_engine)
                options = engine.get("options")
                if options:
                    self.options_store.clear()
                    for option in options:
                        key = option["name"]
                        val = option
                        if option["type"] != "button":
                            val["default"] = option.get("default")
                            val["value"] = option.get("value", val["default"])
                        self.options_store.append([key, val])

        def update_store(*args):
            newGameDialog.createPlayerUIGlobals(discoverer)
            engine_names = [row[1] for row in allstore]
            new_items = []
            # don't add the very first (Human) player to engine store
            for item in newGameDialog.playerItems[0][1:]:
                if item[1] not in engine_names:
                    new_items.append(item)
            ts_iter = None
            for item in new_items:
                ts_iter = allstore.append(item)
            if ts_iter is not None:
                text_select = self.tv.get_selection()
                text_select.select_iter(ts_iter)
            update_options()

        update_store()

        def do_update_store(*args):
            GLib.idle_add(update_store)

        discoverer.connect_after("engine_discovered", do_update_store)

        ################################################################
        # remove button
        ################################################################
        def remove(button):
            if self.cur_engine is not None:
                self.widgets['remove_engine_button'].set_sensitive(False)
                # engine = discoverer.getEngineByName(self.cur_engine)
                discoverer.removeEngine(self.cur_engine)
                discoverer.save()

                selection = self.tv.get_selection()
                result = selection.get_selected()
                if result is not None:
                    model, ts_iter = result
                    model.remove(ts_iter)

                # Notify playerCombos in NewGameTasker
                discoverer.emit("all_engines_discovered")

        self.widgets["remove_engine_button"].connect("clicked", remove)

        ################################################################
        # add button
        ################################################################
        engine_chooser_dialog = Gtk.FileChooserDialog(
            _("Select engine"), None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        filter = Gtk.FileFilter()
        filter.set_name(_("Executable files"))
        filter.add_mime_type("application/x-executable")
        filter.add_mime_type("application/x-ms-dos-executable")
        filter.add_mime_type("application/x-msdownload")
        filter.add_pattern("*.exe")
        for vm in VM_LIST:
            filter.add_pattern("*%s" % vm.ext)

        engine_chooser_dialog.add_filter(filter)
        self.add = False

        def add(button):
            self.add = True
            response = engine_chooser_dialog.run()

            if response == Gtk.ResponseType.OK:
                new_engine = engine_chooser_dialog.get_filename()
                vm_name = None
                vm_args = None
                vmpath = ""
                if new_engine.lower().endswith(
                        ".exe") and sys.platform != "win32":
                    vm_name = "wine"
                    vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK)
                    if vmpath is None:
                        msg_dia = Gtk.MessageDialog(type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(
                            _("<big><b>Unable to add %s</b></big>" %
                              new_engine))
                        msg_dia.format_secondary_text(_("wine not installed"))
                        msg_dia.run()
                        msg_dia.hide()
                        new_engine = ""

                for vm in VM_LIST:
                    ext = os.path.splitext(new_engine)[1]
                    if ext == vm.ext:
                        vm_name = vm.name
                        vm_args = vm.args
                        vmpath = shutil.which(vm_name, mode=os.R_OK | os.X_OK)
                        if vmpath is None:
                            msg_dia = Gtk.MessageDialog(
                                type=Gtk.MessageType.ERROR,
                                buttons=Gtk.ButtonsType.OK)
                            msg_dia.set_markup(
                                _("<big><b>Unable to add %s</b></big>" %
                                  new_engine))
                            msg_dia.format_secondary_text(
                                vm_name + _(" is not installed"))
                            msg_dia.run()
                            msg_dia.hide()
                            new_engine = ""
                        break

                if new_engine:
                    vm_ext_list = [vm.ext for vm in VM_LIST]
                    if ext not in vm_ext_list and not os.access(
                            new_engine, os.X_OK):
                        msg_dia = Gtk.MessageDialog(type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(
                            _("<big><b>%s is not marked executable in the filesystem</b></big>"
                              % new_engine))
                        msg_dia.format_secondary_text(
                            _("Try chmod a+x %s" % new_engine))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return

                    try:
                        engine_command = []
                        if vmpath:
                            engine_command.append(vmpath)
                        if vm_args is not None:
                            engine_command.append(vm_args)
                        engine_command.append(new_engine)
                        # Some engines support CECP and UCI, but main variant engines are CECP,
                        # so we better to start with CECP this case
                        variant_engines = ("fmax", "sjaakii", "sjeng")
                        if any((True for eng in variant_engines
                                if eng in new_engine.lower())):
                            checkers = [is_cecp, is_uci]
                        else:
                            checkers = [is_uci, is_cecp]

                        uci = False
                        for checker in checkers:
                            check_ok = checker(engine_command)
                            if check_ok:
                                uci = checker is is_uci
                                break
                            else:
                                continue
                            if not check_ok:
                                # restore the original
                                engine = discoverer.getEngineByName(
                                    self.cur_engine)
                                engine_chooser_dialog.set_filename(
                                    engine["command"])
                                msg_dia = Gtk.MessageDialog(
                                    type=Gtk.MessageType.ERROR,
                                    buttons=Gtk.ButtonsType.OK)
                                msg_dia.set_markup(
                                    _("<big><b>Unable to add %s</b></big>" %
                                      new_engine))
                                msg_dia.format_secondary_text(
                                    _("There is something wrong with this executable"
                                      ))
                                msg_dia.run()
                                msg_dia.hide()
                                engine_chooser_dialog.hide()
                                self.add = False
                                engine_chooser_dialog.hide()
                                return

                        binname = os.path.split(new_engine)[1]
                        for eng in discoverer.getEngines():
                            if eng["name"] == binname:
                                binname = eng["name"] + "(1)"
                                break

                        self.widgets["engine_command_entry"].set_text(
                            new_engine)
                        self.widgets["engine_protocol_combo"].set_active(
                            0 if uci else 1)
                        self.widgets["engine_args_entry"].set_text("")

                        # active = self.widgets["engine_protocol_combo"].get_active()
                        protocol = "uci" if uci else "xboard"

                        if vm_args is not None:
                            vm_args = vm_args.split(",")
                        # print(binname, new_engine, protocol, vm_name, vm_args)
                        discoverer.addEngine(binname, new_engine, protocol,
                                             vm_name, vm_args)
                        self.cur_engine = binname
                        self.add = False
                        discoverer.discover()
                    except:
                        msg_dia = Gtk.MessageDialog(type=Gtk.MessageType.ERROR,
                                                    buttons=Gtk.ButtonsType.OK)
                        msg_dia.set_markup(
                            _("<big><b>Unable to add %s</b></big>" %
                              new_engine))
                        msg_dia.format_secondary_text(
                            _("There is something wrong with this executable"))
                        msg_dia.run()
                        msg_dia.hide()
                        self.add = False
                        engine_chooser_dialog.hide()
                        return
                else:
                    # restore the original
                    engine = discoverer.getEngineByName(self.cur_engine)
                    engine_chooser_dialog.set_filename(engine["command"])

            engine_chooser_dialog.hide()

        self.widgets["add_engine_button"].connect("clicked", add)

        ################################################################
        # vm args
        ################################################################
        def vm_args_changed(widget):
            if self.cur_engine is not None:
                new_args = self.widgets["vm_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("vm_args")
                if new_args != old_args:
                    engine["vm_args"] = new_args.split()
                    discoverer.save()

        self.widgets["vm_args_entry"].connect("changed", vm_args_changed)

        ################################################################
        # engine args
        ################################################################
        def args_changed(widget):
            if self.cur_engine is not None:
                new_args = self.widgets["engine_args_entry"].get_text().strip()
                engine = discoverer.getEngineByName(self.cur_engine)
                old_args = engine.get("args")
                if new_args != old_args:
                    engine["args"] = new_args.split()
                    discoverer.save()

        self.widgets["engine_args_entry"].connect("changed", args_changed)

        ################################################################
        # engine working directory
        ################################################################
        dir_chooser_dialog = Gtk.FileChooserDialog(
            _("Select working directory"), None,
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        dir_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            dir_chooser_dialog)

        self.widgets["dirChooserDock"].add(dir_chooser_button)
        dir_chooser_button.show()

        def select_dir(button):
            new_directory = dir_chooser_dialog.get_filename()
            engine = discoverer.getEngineByName(self.cur_engine)
            old_directory = engine.get("workingDirectory")
            if new_directory != old_directory and new_directory != self.default_workdir:
                engine["workingDirectory"] = new_directory
                discoverer.save()

        dir_chooser_button.connect("current-folder-changed", select_dir)

        ################################################################
        # engine protocol
        ################################################################
        def protocol_changed(widget):
            if self.cur_engine is not None and not self.add and not self.selection:
                active = self.widgets["engine_protocol_combo"].get_active()
                new_protocol = "uci" if active == 0 else "xboard"
                engine = discoverer.getEngineByName(self.cur_engine)
                old_protocol = engine["protocol"]
                if new_protocol != old_protocol:
                    command = engine.get("command")
                    engine_command = []
                    vm_command = engine.get("vm_command")
                    if vm_command is not None:
                        engine_command.append(vm_command)
                        vm_args = engine.get("vm_args")
                        if vm_args is not None:
                            engine_command.append(", ".join(vm_args))
                    engine_command.append(command)

                    # is the new protocol supported by the engine?
                    if new_protocol == "uci":
                        check_ok = is_uci(engine_command)
                    else:
                        check_ok = is_cecp(engine_command)

                    if check_ok:
                        # discover engine options for new protocol
                        engine["protocol"] = new_protocol
                        engine["recheck"] = True
                        discoverer.discover()
                    else:
                        # restore the original protocol
                        widgets["engine_protocol_combo"].set_active(
                            0 if old_protocol == "uci" else 1)

        self.widgets["engine_protocol_combo"].connect("changed",
                                                      protocol_changed)

        ################################################################
        # engine tree
        ################################################################
        self.selection = False

        def selection_changed(treeselection):
            store, tv_iter = self.tv.get_selection().get_selected()
            if tv_iter:
                self.selection = True
                path = store.get_path(tv_iter)
                indices = path.get_indices()
                row = indices[0]
                name = store[row][1]
                self.cur_engine = name
                engine = discoverer.getEngineByName(name)
                self.widgets['copy_engine_button'].set_sensitive(True)
                if "PyChess.py" in engine["command"]:
                    self.widgets['remove_engine_button'].set_sensitive(False)
                else:
                    self.widgets['remove_engine_button'].set_sensitive(True)
                self.widgets["engine_command_entry"].set_text(
                    engine["command"])
                engine_chooser_dialog.set_filename(engine["command"])
                args = [] if engine.get("args") is None else engine.get("args")
                self.widgets["engine_args_entry"].set_text(' '.join(args))

                vm = engine.get("vm_command")
                self.widgets["vm_command_entry"].set_text(
                    vm if vm is not None else "")
                args = [] if engine.get("vm_args") is None else engine.get(
                    "vm_args")
                self.widgets["vm_args_entry"].set_text(' '.join(args))

                directory = engine.get("workingDirectory")
                dir_choice = directory if directory is not None else self.default_workdir
                dir_chooser_dialog.set_current_folder(dir_choice)
                self.widgets["engine_protocol_combo"].set_active(
                    0 if engine["protocol"] == "uci" else 1)
                update_options()
                self.selection = False

        tree_selection = self.tv.get_selection()
        tree_selection.connect('changed', selection_changed)
        tree_selection.select_path((0, ))
Beispiel #26
0
    def __init__(self):
        self.widgets = uistuff.GladeWidgets("analyze_game.glade")
        self.widgets["analyze_game"].set_transient_for(mainwindow())
        self.stop_event = asyncio.Event()

        uistuff.keep(self.widgets["fromCurrent"], "fromCurrent")
        uistuff.keep(self.widgets["shouldBlack"], "shouldBlack")
        uistuff.keep(self.widgets["shouldWhite"], "shouldWhite")
        uistuff.keep(self.widgets["threatPV"], "threatPV")
        uistuff.keep(self.widgets["showEval"], "showEval")
        uistuff.keep(self.widgets["showBlunder"], "showBlunder")
        uistuff.keep(self.widgets["max_analysis_spin"], "max_analysis_spin")
        uistuff.keep(self.widgets["variation_threshold_spin"],
                     "variation_threshold_spin")

        # Analyzing engines
        uistuff.createCombo(self.widgets["ana_combobox"], name="ana_combobox")

        from pychess.widgets import newGameDialog

        def update_analyzers_store(discoverer):
            data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
            uistuff.updateCombo(self.widgets["ana_combobox"], data)

        discoverer.connect_after("all_engines_discovered",
                                 update_analyzers_store)
        update_analyzers_store(discoverer)

        uistuff.keep(
            self.widgets["ana_combobox"], "ana_combobox", anal_combo_get_value,
            lambda combobox, value: anal_combo_set_value(
                combobox, value, "hint_mode", HINT))

        def hide_window(button, *args):
            self.widgets["analyze_game"].destroy()

        def abort():
            self.analyzer.pause()
            if self.threat_PV:
                self.inv_analyzer.pause()
            self.stop_event.set()
            self.widgets["analyze_game"].destroy()

        def run_analyze(button, *args):
            @asyncio.coroutine
            def coro():
                persp = perspective_manager.get_perspective("games")
                gmwidg = persp.cur_gmwidg()
                gamemodel = gmwidg.gamemodel

                old_check_value = conf.get("analyzer_check")
                conf.set("analyzer_check", True)
                if HINT not in gamemodel.spectators:
                    try:
                        yield from asyncio.wait_for(
                            gamemodel.start_analyzer(HINT), 5.0)
                    except asyncio.TimeoutError:
                        log.error(
                            "Got timeout error while starting hint analyzer")
                        return
                    except Exception:
                        log.error("Unknown error while starting hint analyzer")
                        return
                self.analyzer = gamemodel.spectators[HINT]
                gmwidg.menuitems["hint_mode"].active = True
                self.threat_PV = conf.get("ThreatPV")
                if self.threat_PV:
                    old_inv_check_value = conf.get("inv_analyzer_check")
                    conf.set("inv_analyzer_check", True)
                    if SPY not in gamemodel.spectators:
                        try:
                            yield from asyncio.wait_for(
                                gamemodel.start_analyzer(SPY), 5.0)
                        except asyncio.TimeoutError:
                            log.error(
                                "Got timeout error while starting spy analyzer"
                            )
                            return
                        except Exception:
                            log.error(
                                "Unknown error while starting spy analyzer")
                            return
                    inv_analyzer = gamemodel.spectators[SPY]
                    gmwidg.menuitems["spy_mode"].active = True

                title = _("Game analyzing in progress...")
                text = _("Do you want to abort it?")
                content = InfoBar.get_message_content(
                    title, text, Gtk.STOCK_DIALOG_QUESTION)

                def response_cb(infobar, response, message):
                    conf.set("analyzer_check", old_check_value)
                    if self.threat_PV:
                        conf.set("inv_analyzer_check", old_inv_check_value)
                    message.dismiss()
                    abort()

                message = InfoBarMessage(Gtk.MessageType.QUESTION, content,
                                         response_cb)
                message.add_button(
                    InfoBarMessageButton(_("Abort"), Gtk.ResponseType.CANCEL))
                gmwidg.replaceMessages(message)

                @asyncio.coroutine
                def analyse_moves():
                    should_black = conf.get("shouldBlack")
                    should_white = conf.get("shouldWhite")
                    from_current = conf.get("fromCurrent")
                    start_ply = gmwidg.board.view.shown if from_current else 0
                    move_time = int(conf.get("max_analysis_spin"))
                    threshold = int(conf.get("variation_threshold_spin"))
                    for board in gamemodel.boards[start_ply:]:
                        if self.stop_event.is_set():
                            break

                        gmwidg.board.view.setShownBoard(board)
                        self.analyzer.setBoard(board)
                        if self.threat_PV:
                            inv_analyzer.setBoard(board)
                        yield from asyncio.sleep(move_time + 0.1)

                        ply = board.ply - gamemodel.lowply
                        color = (ply - 1) % 2
                        if ply - 1 in gamemodel.scores and ply in gamemodel.scores and (
                            (color == BLACK and should_black) or
                            (color == WHITE and should_white)):
                            oldmoves, oldscore, olddepth = gamemodel.scores[ply
                                                                            -
                                                                            1]
                            oldscore = oldscore * -1 if color == BLACK else oldscore
                            score_str = prettyPrintScore(oldscore, olddepth)
                            moves, score, depth = gamemodel.scores[ply]
                            score = score * -1 if color == WHITE else score
                            diff = score - oldscore
                            if ((diff > threshold and color == BLACK) or
                                (diff < -1 * threshold and color == WHITE)
                                ) and (gamemodel.moves[ply - 1] != parseAny(
                                    gamemodel.boards[ply - 1], oldmoves[0])):
                                if self.threat_PV:
                                    try:
                                        if ply - 1 in gamemodel.spy_scores:
                                            oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[
                                                ply - 1]
                                            score_str0 = prettyPrintScore(
                                                oldscore0, olddepth0)
                                            pv0 = listToMoves(
                                                gamemodel.boards[ply - 1],
                                                ["--"] + oldmoves0,
                                                validate=True)
                                            if len(pv0) > 2:
                                                gamemodel.add_variation(
                                                    gamemodel.boards[ply - 1],
                                                    pv0,
                                                    comment="Threatening",
                                                    score=score_str0,
                                                    emit=False)
                                    except ParsingError as e:
                                        # ParsingErrors may happen when parsing "old" lines from
                                        # analyzing engines, which haven't yet noticed their new tasks
                                        log.debug(
                                            "__parseLine: Ignored (%s) from analyzer: ParsingError%s"
                                            % (' '.join(oldmoves), e))
                                try:
                                    pv = listToMoves(gamemodel.boards[ply - 1],
                                                     oldmoves,
                                                     validate=True)
                                    gamemodel.add_variation(
                                        gamemodel.boards[ply - 1],
                                        pv,
                                        comment="Better is",
                                        score=score_str,
                                        emit=False)
                                except ParsingError as e:
                                    # ParsingErrors may happen when parsing "old" lines from
                                    # analyzing engines, which haven't yet noticed their new tasks
                                    log.debug(
                                        "__parseLine: Ignored (%s) from analyzer: ParsingError%s"
                                        % (' '.join(oldmoves), e))

                    self.widgets["analyze_game"].hide()
                    self.widgets["analyze_ok_button"].set_sensitive(True)
                    conf.set("analyzer_check", old_check_value)
                    if self.threat_PV:
                        conf.set("inv_analyzer_check", old_inv_check_value)
                    message.dismiss()

                    gamemodel.emit("analysis_finished")

                create_task(analyse_moves())
                hide_window(None)

                return True

            create_task(coro())

        self.widgets["analyze_game"].connect("delete-event", hide_window)
        self.widgets["analyze_cancel_button"].connect("clicked", hide_window)
        self.widgets["analyze_ok_button"].connect("clicked", run_analyze)
    def __init__(self):
        self.widgets = uistuff.GladeWidgets("analyze_game.glade")
        self.widgets["analyze_game"].set_transient_for(mainwindow())
        self.stop_event = asyncio.Event()

        uistuff.keep(self.widgets["fromCurrent"], "fromCurrent")
        uistuff.keep(self.widgets["shouldBlack"], "shouldBlack")
        uistuff.keep(self.widgets["shouldWhite"], "shouldWhite")
        uistuff.keep(self.widgets["threatPV"], "threatPV")
        uistuff.keep(self.widgets["showEval"], "showEval")
        uistuff.keep(self.widgets["showBlunder"], "showBlunder")
        uistuff.keep(self.widgets["max_analysis_spin"], "max_analysis_spin")
        uistuff.keep(self.widgets["variation_threshold_spin"], "variation_threshold_spin")

        # Analyzing engines
        uistuff.createCombo(self.widgets["ana_combobox"], name="ana_combobox")

        from pychess.widgets import newGameDialog

        def update_analyzers_store(discoverer):
            data = [(item[0], item[1]) for item in newGameDialog.analyzerItems]
            uistuff.updateCombo(self.widgets["ana_combobox"], data)
        discoverer.connect_after("all_engines_discovered", update_analyzers_store)
        update_analyzers_store(discoverer)

        uistuff.keep(self.widgets["ana_combobox"], "ana_combobox", anal_combo_get_value,
                     lambda combobox, value: anal_combo_set_value(combobox, value, "hint_mode", HINT))

        def hide_window(button, *args):
            self.widgets["analyze_game"].destroy()

        def abort():
            self.stop_event.set()
            self.widgets["analyze_game"].destroy()

        def run_analyze(button, *args):
            @asyncio.coroutine
            def coro():
                persp = perspective_manager.get_perspective("games")
                gmwidg = persp.cur_gmwidg()
                gamemodel = gmwidg.gamemodel

                old_check_value = conf.get("analyzer_check")
                conf.set("analyzer_check", True)
                if HINT not in gamemodel.spectators:
                    try:
                        yield from asyncio.wait_for(gamemodel.start_analyzer(HINT), 5.0)
                    except asyncio.TimeoutError:
                        log.error("Got timeout error while starting hint analyzer")
                        return
                    except Exception:
                        log.error("Unknown error while starting hint analyzer")
                        return
                analyzer = gamemodel.spectators[HINT]
                gmwidg.menuitems["hint_mode"].active = True
                threat_PV = conf.get("ThreatPV")
                if threat_PV:
                    old_inv_check_value = conf.get("inv_analyzer_check")
                    conf.set("inv_analyzer_check", True)
                    if SPY not in gamemodel.spectators:
                        try:
                            yield from asyncio.wait_for(gamemodel.start_analyzer(SPY), 5.0)
                        except asyncio.TimeoutError:
                            log.error("Got timeout error while starting spy analyzer")
                            return
                        except Exception:
                            log.error("Unknown error while starting spy analyzer")
                            return
                    inv_analyzer = gamemodel.spectators[SPY]
                    gmwidg.menuitems["spy_mode"].active = True

                title = _("Game analyzing in progress...")
                text = _("Do you want to abort it?")
                content = InfoBar.get_message_content(title, text, Gtk.STOCK_DIALOG_QUESTION)

                def response_cb(infobar, response, message):
                    conf.set("analyzer_check", old_check_value)
                    if threat_PV:
                        conf.set("inv_analyzer_check", old_inv_check_value)
                    message.dismiss()
                    abort()
                message = InfoBarMessage(Gtk.MessageType.QUESTION, content, response_cb)
                message.add_button(InfoBarMessageButton(_("Abort"), Gtk.ResponseType.CANCEL))
                gmwidg.replaceMessages(message)

                @asyncio.coroutine
                def analyse_moves():
                    should_black = conf.get("shouldBlack")
                    should_white = conf.get("shouldWhite")
                    from_current = conf.get("fromCurrent")
                    start_ply = gmwidg.board.view.shown if from_current else 0
                    move_time = int(conf.get("max_analysis_spin"))
                    threshold = int(conf.get("variation_threshold_spin"))
                    for board in gamemodel.boards[start_ply:]:
                        if self.stop_event.is_set():
                            break

                        gmwidg.board.view.setShownBoard(board)
                        analyzer.setBoard(board)
                        if threat_PV:
                            inv_analyzer.setBoard(board)
                        yield from asyncio.sleep(move_time + 0.1)

                        ply = board.ply - gamemodel.lowply
                        color = (ply - 1) % 2
                        if ply - 1 in gamemodel.scores and ply in gamemodel.scores and (
                                (color == BLACK and should_black) or (color == WHITE and should_white)):
                            oldmoves, oldscore, olddepth = gamemodel.scores[ply - 1]
                            oldscore = oldscore * -1 if color == BLACK else oldscore
                            score_str = prettyPrintScore(oldscore, olddepth)
                            moves, score, depth = gamemodel.scores[ply]
                            score = score * -1 if color == WHITE else score
                            diff = score - oldscore
                            if ((diff > threshold and color == BLACK) or (diff < -1 * threshold and color == WHITE)) and (
                               gamemodel.moves[ply - 1] != parseAny(gamemodel.boards[ply - 1], oldmoves[0])):
                                if threat_PV:
                                    try:
                                        if ply - 1 in gamemodel.spy_scores:
                                            oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[ply - 1]
                                            score_str0 = prettyPrintScore(oldscore0, olddepth0)
                                            pv0 = listToMoves(gamemodel.boards[ply - 1], ["--"] + oldmoves0, validate=True)
                                            if len(pv0) > 2:
                                                gamemodel.add_variation(gamemodel.boards[ply - 1], pv0,
                                                                        comment="Threatening", score=score_str0, emit=False)
                                    except ParsingError as e:
                                        # ParsingErrors may happen when parsing "old" lines from
                                        # analyzing engines, which haven't yet noticed their new tasks
                                        log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" %
                                                  (' '.join(oldmoves), e))
                                try:
                                    pv = listToMoves(gamemodel.boards[ply - 1], oldmoves, validate=True)
                                    gamemodel.add_variation(gamemodel.boards[ply - 1], pv,
                                                            comment="Better is", score=score_str, emit=False)
                                except ParsingError as e:
                                    # ParsingErrors may happen when parsing "old" lines from
                                    # analyzing engines, which haven't yet noticed their new tasks
                                    log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" %
                                              (' '.join(oldmoves), e))

                    self.widgets["analyze_game"].hide()
                    self.widgets["analyze_ok_button"].set_sensitive(True)
                    conf.set("analyzer_check", old_check_value)
                    if threat_PV:
                        conf.set("inv_analyzer_check", old_inv_check_value)
                    message.dismiss()

                    gamemodel.emit("analysis_finished")

                create_task(analyse_moves())
                hide_window(None)

                return True
            create_task(coro())

        self.widgets["analyze_game"].connect("delete-event", hide_window)
        self.widgets["analyze_cancel_button"].connect("clicked", hide_window)
        self.widgets["analyze_ok_button"].connect("clicked", run_analyze)