Beispiel #1
0
    def create_database(self):
        dialog = Gtk.FileChooserDialog(
            _("Create New Pgn Database"), mainwindow(), Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_NEW, Gtk.ResponseType.ACCEPT))

        dialog.set_current_folder(os.path.expanduser("~"))
        dialog.set_current_name("new.pgn")

        response = dialog.run()
        if response == Gtk.ResponseType.ACCEPT:
            new_pgn = dialog.get_filename()
            if not new_pgn.endswith(".pgn"):
                new_pgn = "%s.pgn" % new_pgn

            if not os.path.isfile(new_pgn):
                # create new file
                with open(new_pgn, "w"):
                    pass
                self.open_chessfile(new_pgn)
            else:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                      buttons=Gtk.ButtonsType.OK)
                d.set_markup(_("<big><b>File '%s' already exists.</b></big>") % new_pgn)
                d.run()
                d.hide()
                print("%s allready exist." % new_pgn)

        dialog.destroy()
Beispiel #2
0
    def on_selection_changed(self, selection):
        model, iter = selection.get_selected()
        if iter is None:
            self.gamemodel.boards = [Board(FEN_EMPTY)]
            del self.gamemodel.moves[:]
            self.boardview.shown = 0
            self.boardview.redrawCanvas()
            return

        path = self.persp.gamelist.get_model().get_path(iter)

        rec, ply = self.persp.gamelist.get_record(path)
        if rec is None:
            return

        try:
            self.persp.chessfile.loadToModel(rec, -1, self.gamemodel)
        except LoadingError as err:
            dialogue = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                                         buttons=Gtk.ButtonsType.OK,
                                         message_format=err.args[0])
            if len(err.args) > 1:
                dialogue.format_secondary_text(err.args[1])
            dialogue.connect("response", lambda dialogue, a: dialogue.hide())
            dialogue.show()
        self.boardview.lastMove = None
        self.boardview._shown = self.gamemodel.lowply

        self.boardview.redrawCanvas()
        self.boardview.shown = ply if ply > 0 else self.persp.gamelist.ply
Beispiel #3
0
    def on_save_as_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            _("Save as"), mainwindow(), Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.ACCEPT))
        dialog.set_current_folder(os.path.expanduser("~"))

        response = dialog.run()
        if response == Gtk.ResponseType.ACCEPT:
            filename = dialog.get_filename()
        else:
            filename = None

        dialog.destroy()

        if filename is None:
            return

        self.progress_dialog.set_title(_("Save as"))

        def save_as(cancel_event):
            with open(filename, "w") as to_file:
                self.process_records(self.save_records, cancel_event, to_file)

            GLib.idle_add(self.progress_dialog.hide)

        cancel_event = threading.Event()
        loop = asyncio.get_event_loop()
        loop.run_in_executor(None, save_as, cancel_event)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            cancel_event.set()
        self.progress_dialog.hide()
Beispiel #4
0
def on_pick_date(button, date_entry):
    # Parse the existing date
    date = date_entry.get_text()
    year, month, day = parseDateTag(date)

    # Prepare the date of the picker
    calendar = Gtk.Calendar()
    curyear, curmonth, curday = calendar.get_date()
    year = curyear if year is None else year
    month = curmonth if month is None else month - 1
    day = curday if day is None else day
    calendar.select_month(month, year)
    calendar.select_day(day)

    # Show the dialog
    dialog = Gtk.Dialog(_("Pick a date"),
                        mainwindow(),
                        Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                        (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))

    sw = Gtk.ScrolledWindow()
    sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
    sw.add(calendar)

    dialog.get_content_area().pack_start(sw, True, True, 0)
    dialog.resize(300, 200)
    dialog.show_all()

    response = dialog.run()
    dialog.destroy()

    if response == Gtk.ResponseType.ACCEPT:
        year, month, day = calendar.get_date()
        date_entry.set_text("%04d.%02d.%02d" % (year, month + 1, day))
Beispiel #5
0
 def load_from_xml(self):
     if os.path.isfile(self.dockLocation):
         try:
             self.dock.loadFromXML(self.dockLocation, self.docks)
         except Exception as e:
             # We don't send error message when error caused by no more existing SwitcherPanel
             if e.args[0] != "SwitcherPanel" and "unittest" not in sys.modules.keys():
                 stringio = StringIO()
                 traceback.print_exc(file=stringio)
                 error = stringio.getvalue()
                 log.error("Dock loading error: %s\n%s" % (e, error))
                 msg_dia = Gtk.MessageDialog(mainwindow(),
                                             type=Gtk.MessageType.ERROR,
                                             buttons=Gtk.ButtonsType.CLOSE)
                 msg_dia.set_markup(_(
                     "<b><big>PyChess was unable to load your panel settings</big></b>"))
                 msg_dia.format_secondary_text(_(
                     "Your panel settings have been reset. If this problem repeats, \
                     you should report it to the developers"))
                 msg_dia.run()
                 msg_dia.hide()
             os.remove(self.dockLocation)
             for title, panel, menu_item in self.docks.values():
                 title.unparent()
                 panel.unparent()
Beispiel #6
0
    def on_import_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            _("Open chess file"), mainwindow(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        dialog.set_select_multiple(True)

        filter_text = Gtk.FileFilter()
        filter_text.set_name(".pgn")
        filter_text.add_pattern("*.pgn")
        filter_text.add_mime_type("application/x-chess-pgn")
        dialog.add_filter(filter_text)

        filter_text = Gtk.FileFilter()
        filter_text.set_name(".zip")
        filter_text.add_pattern("*.zip")
        filter_text.add_mime_type("application/zip")
        dialog.add_filter(filter_text)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            filenames = dialog.get_filenames()
        else:
            filenames = None

        dialog.destroy()

        if filenames is not None:
            self.do_import(filenames)

            response = self.progress_dialog.run()
            if response == Gtk.ResponseType.CANCEL:
                self.importer.do_cancel()
            self.progress_dialog.hide()
Beispiel #7
0
    def on_save_as_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            _("Save as"), mainwindow(), Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.ACCEPT))
        dialog.set_current_folder(os.path.expanduser("~"))

        response = dialog.run()
        if response == Gtk.ResponseType.ACCEPT:
            filename = dialog.get_filename()
        else:
            filename = None

        dialog.destroy()

        if filename is not None:
            with open(filename, "w") as to_file:
                records, plys = self.chessfile.get_records(FIRST_PAGE)
                self.save_records(records, to_file)
                while True:
                    records, plys = self.chessfile.get_records(NEXT_PAGE)
                    if records:
                        self.save_records(records, to_file)
                    else:
                        break
Beispiel #8
0
def get_save_dialog(export=False):
    savedialog = Gtk.FileChooserDialog(
        "", mainwindow(), Gtk.FileChooserAction.SAVE,
        (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
         Gtk.ResponseType.ACCEPT))
    savedialog.set_current_folder(os.path.expanduser("~"))

    # Add widgets to the savedialog
    savecombo = Gtk.ComboBox()
    savecombo.set_name("savecombo")

    crt = Gtk.CellRendererText()
    savecombo.pack_start(crt, True)
    savecombo.add_attribute(crt, 'text', 0)

    crt = Gtk.CellRendererText()
    savecombo.pack_start(crt, False)
    savecombo.add_attribute(crt, 'text', 1)

    if export:
        savecombo.set_model(exportformats)
    else:
        savecombo.set_model(saveformats)

    savecombo.set_active(1)  # pgn
    savedialog.set_extra_widget(savecombo)

    return savedialog, savecombo
Beispiel #9
0
def get_open_dialog():
    opendialog = Gtk.FileChooserDialog(
        _("Open chess file"), mainwindow(), Gtk.FileChooserAction.OPEN,
        (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
         Gtk.ResponseType.OK))
    opendialog.set_show_hidden(True)
    opendialog.set_select_multiple(True)

    # All chess files filter
    all_filter = Gtk.FileFilter()
    all_filter.set_name(_("All Chess Files"))
    opendialog.add_filter(all_filter)
    opendialog.set_filter(all_filter)

    # Specific filters and save formats
    for ending, saver in enddir.items():
        label = saver.__label__
        endstr = "(%s)" % ending
        f = Gtk.FileFilter()
        f.set_name(label + " " + endstr)
        if hasattr(saver, "load"):
            f.add_pattern("*." + ending)
            all_filter.add_pattern("*." + ending)
            opendialog.add_filter(f)

    return opendialog
    def __init__(self):
        self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL, title=_("Ask for permissions"))
        self.window.set_transient_for(mainwindow())
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        gtk_version = (Gtk.get_major_version(), Gtk.get_minor_version())
        if gtk_version >= (3, 12):
            vbox.props.margin_start = 9
            vbox.props.margin_end = 9
        else:
            vbox.props.margin_left = 9
            vbox.props.margin_right = 9
        vbox.props.margin_bottom = 9
        self.window.add(vbox)
        uistuff.keepWindowSize("externalsdialog", self.window, (320, 240), uistuff.POSITION_CENTER)

        label = Gtk.Label(_("Some of PyChess features needs your permission to download external programs"))
        vbox.pack_start(label, True, True, 0)

        box = Gtk.Box()
        check_button = Gtk.CheckButton(_("database querying needs scoutfish"))
        check_button.set_active(conf.get("download_scoutfish", False))
        check_button.connect("toggled", lambda w: conf.set("download_scoutfish", w.get_active()))
        box.add(check_button)
        link = "https://github.com/pychess/scoutfish"
        link_button = Gtk.LinkButton(link, link)
        box.add(link_button)
        vbox.pack_start(box, False, False, 0)

        box = Gtk.Box()
        check_button = Gtk.CheckButton(_("database opening tree needs chess_db"))
        check_button.set_active(conf.get("download_chess_db", False))
        check_button.connect("toggled", lambda w: conf.set("download_chess_db", w.get_active()))
        box.add(check_button)
        link = "https://github.com/pychess/chess_db"
        link_button = Gtk.LinkButton(link, link)
        box.add(link_button)
        vbox.pack_start(box, False, False, 0)

        box = Gtk.Box()
        check_button = Gtk.CheckButton(_("ICC lag compensation needs timestamp"))
        check_button.set_active(conf.get("download_timestamp", False))
        check_button.connect("toggled", lambda w: conf.set("download_timestamp", w.get_active()))
        box.add(check_button)
        link = "https://www.chessclub.com/user/resources/icc/timestamp"
        link_button = Gtk.LinkButton(link, link)
        box.add(link_button)
        vbox.pack_start(box, False, False, 0)

        check_button = Gtk.CheckButton(_("Don't show this dialog on startup."))
        check_button.set_active(conf.get("dont_show_externals_at_startup", False))
        check_button.connect("toggled", lambda w: conf.set("dont_show_externals_at_startup", w.get_active()))
        vbox.pack_start(check_button, True, True, 0)

        buttonbox = Gtk.ButtonBox()
        close_button = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
        close_button.connect("clicked", self.on_close_clicked)
        self.window.connect("delete_event", lambda w, a: self.window.destroy())
        buttonbox.add(close_button)
        vbox.pack_start(buttonbox, False, False, 0)
Beispiel #11
0
def run():
    global dialog
    dialog.widgets["fics_logon"].set_transient_for(mainwindow())

    if dialog.lounge:
        dialog.lounge.present()
    else:
        dialog.present()
Beispiel #12
0
def paste(gamemodel):
    dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO)
    if gamemodel.status in UNDOABLE_STATES:
        text = _("The current game is over. First, please verify the properties of the game.")
    else:
        text = _("The current game is not terminated. Its export may have a limited interest.")
    text += "\n\n" + _("Should %s publicly publish your game as PGN on chesspastebin.com ?") % NAME
    dialog.set_markup(text)
    response = dialog.run()
    dialog.destroy()
    if response != Gtk.ResponseType.YES:
        return

    output = StringIO()
    text = pgn.save(output, gamemodel)
    values = {'apikey': APIKEY,
              'pgn': text,
              "name": "PyChess",
              'sandbox': 'false'}

    data = urlencode(values).encode('utf-8')
    req = Request(URL, data)
    try:
        response = urlopen(req, timeout=10)
    except URLError as err:
        if hasattr(err, 'reason'):
            print('We failed to reach the server.')
            print('Reason: ', err.reason)
        elif hasattr(err, 'code'):
            print('The server couldn\'t fulfill the request.')
            print('Error code: ', err.code)
    else:
        ID = response.read()
        link = "http://www.chesspastebin.com/?p=%s" % int(ID)
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        clipboard.set_text(link, -1)
        # print(text)
        # print(clipboard.wait_for_text())
        msg_dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO,
                                       buttons=Gtk.ButtonsType.OK)
        msg = _(
            "Game shared at ") + '<a href="%s">chesspastebin.com</a>' % link
        msg_dialog.set_markup(msg)
        msg_dialog.format_secondary_text(_("(Link is available on clipboard.)"))
        msg_dialog.connect("response", lambda msg_dialog, a: msg_dialog.hide())
        msg_dialog.show()
Beispiel #13
0
 def engineDead(self, engine, gmwidg):
     gmwidg.bringToFront()
     dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                buttons=Gtk.ButtonsType.OK)
     dialog.set_markup(_("<big><b>Engine, %s, has died</b></big>") % repr(engine))
     dialog.format_secondary_text(_(
         "PyChess has lost connection to the engine, probably because it has died.\n\n \
         You can try to start a new game with the engine, or try to play against another one."))
     dialog.connect("response", lambda dialog, r: dialog.hide())
     dialog.show_all()
Beispiel #14
0
    def notify(new_version):
        msg_dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO,
                                       buttons=Gtk.ButtonsType.OK)

        msg = _("<b>New version %s is available!</b>" % new_version)
        msg_dialog.set_markup(msg)
        msg_dialog.format_secondary_markup('<a href="%s">%s</a>' % (LINK, LINK))

        msg_dialog.connect("response", lambda msg_dialog, a: msg_dialog.hide())
        msg_dialog.show()
Beispiel #15
0
    def __init__(self):
        self.widgets = uistuff.GladeWidgets("tipoftheday.glade")
        self.widgets["window1"].set_transient_for(mainwindow())
        uistuff.keepWindowSize("tipoftheday", self.widgets["window1"], (320, 240), uistuff.POSITION_CENTER)

        self.widgets["checkbutton1"].set_active(conf.get("show_tip_at_startup"))
        self.widgets["checkbutton1"].connect("toggled", lambda w: conf.set("show_tip_at_startup", w.get_active()))
        self.widgets["close_button"].connect("clicked", lambda w: self.widgets["window1"].emit("delete-event", None))
        self.widgets["window1"].connect("delete_event", lambda w, a: self.widgets["window1"].destroy())
        self.widgets["back_button"].connect("clicked", lambda w: self.set_currentIndex(self.currentIndex - 1))
        self.widgets["forward_button"].connect("clicked", lambda w: self.set_currentIndex(self.currentIndex + 1))

        self.currentIndex = 0
    def __init__(self, widgets):
        # Init 'auto save" checkbutton
        def checkCallBack(_):
            """ :Description: Sets the various option based on user interaction with the
                checkboxes in the gui
            """

            checkbox = widgets["autoSave"]
            widgets["autosave_grid"].set_property("sensitive", checkbox.get_active())

        conf.notify_add("autoSave", checkCallBack)
        uistuff.keep(widgets["autoSave"], "autoSave", first_value=True)
        checkCallBack(_)

        default_path = os.path.expanduser("~")
        self.auto_save_path = conf.get("autoSavePath", default_path)
        conf.set("autoSavePath", self.auto_save_path)

        auto_save_chooser_dialog = Gtk.FileChooserDialog(
            _("Select auto save path"), mainwindow(),
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        auto_save_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            auto_save_chooser_dialog)
        auto_save_chooser_button.set_current_folder(self.auto_save_path)

        widgets["savePathChooserDock"].add(auto_save_chooser_button)
        auto_save_chooser_button.show()

        def selectAutoSave(_):
            """ :Description: Sets the auto save path for stored games if it
                has changed since last time

                :signal: Activated on receiving the 'current-folder-changed' signal
            """
            new_directory = auto_save_chooser_dialog.get_filename()
            if new_directory != self.auto_save_path:
                conf.set("autoSavePath", new_directory)

        auto_save_chooser_button.connect("current-folder-changed", selectAutoSave)

        conf.set("autoSaveFormat", conf.get("autoSaveFormat", "pychess"))
        uistuff.keep(widgets["autoSaveFormat"], "autoSaveFormat")

        uistuff.keep(widgets["saveEmt"], "saveEmt")
        uistuff.keep(widgets["saveEval"], "saveEval")
        uistuff.keep(widgets["saveRatingChange"], "saveRatingChange")
        uistuff.keep(widgets["indentPgn"], "indentPgn")
        uistuff.keep(widgets["saveOwnGames"], "saveOwnGames", first_value=True)
Beispiel #17
0
 def _validate(gamemodel):
     try:
         fenstr = cls.get_fen()
         cls.setupmodel.variant(setup=fenstr)
         return True
     except (AssertionError, LoadingError, SyntaxError) as e:
         d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                               buttons=Gtk.ButtonsType.OK,
                               message_format=e.args[0])
         if len(e.args) > 1:
             d.format_secondary_text(e.args[1])
         d.connect("response", lambda d, a: d.hide())
         d.show()
         return False
    def panel_about(self, button):
        store, iter = self.tv.get_selection().get_selected()
        assert iter  # The button should only be clickable when we have a selection
        path = store.get_path(iter)
        panel = store[path][3]

        d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO,
                              buttons=Gtk.ButtonsType.CLOSE)
        d.set_markup("<big><b>%s</b></big>" % panel.__title__)
        text = panel.__about__ if hasattr(
            panel, '__about__') else _('Undescribed panel')
        d.format_secondary_text(text)
        d.run()
        d.hide()
Beispiel #19
0
 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()
Beispiel #20
0
 def _validate(gamemodel):
     try:
         text, loadType = _get_text()
         chessfile = loadType.load(StringIO(text))
         chessfile.loadToModel(chessfile.games[0], -1, model=gamemodel)
         gamemodel.status = WAITING_TO_START
         return True
     except LoadingError as e:
         d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                               buttons=Gtk.ButtonsType.OK,
                               message_format=e.args[0])
         d.format_secondary_text(e.args[1])
         d.connect("response", lambda d, a: d.hide())
         d.show()
         return False
Beispiel #21
0
    def create_book(self, new_bin=None):
        if new_bin is None:
            dialog = Gtk.FileChooserDialog(
                _("Create New Polyglot Opening Book"), mainwindow(), Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_NEW, Gtk.ResponseType.ACCEPT))

            dialog.set_current_folder(os.path.expanduser("~"))
            dialog.set_current_name("new_book.bin")

            response = dialog.run()
            if response == Gtk.ResponseType.ACCEPT:
                new_bin = dialog.get_filename()
                if not new_bin.endswith(".bin"):
                    new_bin = "%s.bin" % new_bin
            dialog.destroy()

        if new_bin is None:
            return

        self.progress_dialog.set_title(_("Create Polyglot Book"))

        def creating_book(cancel_event):
            positions = {}
            self.process_records(self.feed_book, cancel_event, positions)

            if cancel_event.is_set():
                return

            with open(new_bin, "wb") as to_file:
                GLib.idle_add(self.progressbar.set_text, _("Save"))
                for key, moves in sorted(positions.items(), key=lambda item: item[0]):
                    # print(key, moves)
                    for move in moves:
                        to_file.write(pack(">QHHI", key, move, moves[move], 0))
            GLib.idle_add(self.emit, "bookfile_created")
            GLib.idle_add(self.progress_dialog.hide)

        cancel_event = threading.Event()
        loop = asyncio.get_event_loop()
        loop.run_in_executor(None, creating_book, cancel_event)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            cancel_event.set()
        self.progress_dialog.hide()
Beispiel #22
0
        def cancel_event(widget, with_confirmation, *args):
            # Confirm if the changes need to be saved
            modified = discoverer.hasChanged()
            if modified and with_confirmation:
                dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO)
                dialog.set_markup(_("You have unsaved changes. Do you want to save before leaving?"))
                response = dialog.run()
                dialog.destroy()
                # if response == Gtk.ResponseType.CANCEL:
                #    return False
                if response == Gtk.ResponseType.NO:
                    discoverer.restore()
                if response == Gtk.ResponseType.YES:
                    discoverer.save()

            # Close the window
            widgets["manage_engines_dialog"].hide()
            return True
Beispiel #23
0
    def __init__(self, image, child):
        GObject.GObject.__init__(self)
        self.add(image)

        self.subwindow = Gtk.Window()
        self.subwindow.set_transient_for(mainwindow())
        self.subwindow.set_decorated(False)
        self.subwindow.set_resizable(False)
        self.subwindow.set_type_hint(Gdk.WindowTypeHint.DIALOG)
        self.subwindow.add(child)
        self.subwindow.connect_after("draw", self.__sub_onExpose)
        self.subwindow.connect("button_press_event", self.__sub_onPress)
        # self.subwindow.connect("motion_notify_event", self.__sub_onMotion)
        # self.subwindow.connect("leave_notify_event", self.__sub_onMotion)
        # self.subwindow.connect("delete-event", self.__sub_onDelete)
        self.subwindow.connect("focus-out-event", self.__sub_onFocusOut)
        child.show_all()

        self.setOpen(False)
        self.connect("button_press_event", self.__onPress)
Beispiel #24
0
    def onHelperConnectionError(self, connection, error):
        if self.helperconn is not None:
            dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION,
                                       buttons=Gtk.ButtonsType.YES_NO)
            dialog.set_markup(_("Guest logins disabled by FICS server"))
            text = "PyChess can maintain users status and games list only if it changes\n\
            'open', 'gin' and 'availinfo' user variables.\n\
            Do you enable to set these variables on?"
            dialog.format_secondary_text(text)
            response = dialog.run()
            dialog.destroy()

            self.helperconn.cancel()
            self.helperconn.close()
            self.helperconn = None

            set_user_vars = response == Gtk.ResponseType.YES

            @asyncio.coroutine
            def coro():
                yield from self.main_connected_event.wait()
                self.connection.start_helper_manager(set_user_vars)
            asyncio.async(coro())
Beispiel #25
0
 def onAssessReceived(self, glm, assess):
     if self.assess_sent:
         self.assess_sent = False
         dialog = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.INFO,
                                    buttons=Gtk.ButtonsType.OK)
         dialog.set_title(_("Assess"))
         dialog.set_markup(_("Effect on ratings by the possible outcomes"))
         grid = Gtk.Grid()
         grid.set_column_homogeneous(True)
         grid.set_row_spacing(12)
         grid.set_row_spacing(12)
         name0 = Gtk.Label()
         name0.set_markup("<b>%s</b>" % assess["names"][0])
         name1 = Gtk.Label()
         name1.set_markup("<b>%s</b>" % assess["names"][1])
         grid.attach(Gtk.Label(""), 0, 0, 1, 1)
         grid.attach(name0, 1, 0, 1, 1)
         grid.attach(name1, 2, 0, 1, 1)
         grid.attach(Gtk.Label(assess["type"]), 0, 1, 1, 1)
         grid.attach(Gtk.Label(assess["oldRD"][0]), 1, 1, 1, 1)
         grid.attach(Gtk.Label(assess["oldRD"][1]), 2, 1, 1, 1)
         grid.attach(Gtk.Label(_("Win:")), 0, 2, 1, 1)
         grid.attach(Gtk.Label(assess["win"][0]), 1, 2, 1, 1)
         grid.attach(Gtk.Label(assess["win"][1]), 2, 2, 1, 1)
         grid.attach(Gtk.Label(_("Draw:")), 0, 3, 1, 1)
         grid.attach(Gtk.Label(assess["draw"][0]), 1, 3, 1, 1)
         grid.attach(Gtk.Label(assess["draw"][1]), 2, 3, 1, 1)
         grid.attach(Gtk.Label(_("Loss:")), 0, 4, 1, 1)
         grid.attach(Gtk.Label(assess["loss"][0]), 1, 4, 1, 1)
         grid.attach(Gtk.Label(assess["loss"][1]), 2, 4, 1, 1)
         grid.attach(Gtk.Label(_("New RD:")), 0, 5, 1, 1)
         grid.attach(Gtk.Label(assess["newRD"][0]), 1, 5, 1, 1)
         grid.attach(Gtk.Label(assess["newRD"][1]), 2, 5, 1, 1)
         grid.show_all()
         dialog.get_message_area().add(grid)
         dialog.run()
         dialog.destroy()
Beispiel #26
0
    def __init__(self, widgets):
        self.widgets = widgets

        # Options on by default
        for key in ("opening_check", "endgame_check", "online_egtb_check",
                    "inv_analyzer_check"):
            uistuff.keep(widgets[key], key, first_value=False)
        uistuff.keep(widgets["analyzer_check"],
                     "analyzer_check",
                     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

        engine = discoverer.getEngineByName(discoverer.getEngineLearn())
        if engine is None:
            engine = discoverer.getEngineN(-1)
        default = engine.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)
        uistuff.keep(self.widgets["infinite_analysis"],
                     "infinite_analysis",
                     first_value=False)
Beispiel #27
0
        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()
Beispiel #28
0
    def _init(cls):
        cls.widgets = uistuff.GladeWidgets("newInOut.glade")
        cls.widgets["newgamedialog"].set_transient_for(mainwindow())

        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)
    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)
Beispiel #30
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                if line[0:1] == "#":
                    # Debug line which we shall ignore as specified in CECPv2 specs
                    continue

        #        log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname})
                parts = whitespaces.split(line.strip())
                if parts[0] == "pong":
                    self.lastpong = int(parts[1])
                    continue

                # Illegal Move
                if parts[0].lower().find("illegal") >= 0:
                    log.warning(
                        "__parseLine: illegal move: line=\"%s\", board=%s" %
                        (line.strip(), self.board),
                        extra={"task": self.defname})
                    if parts[-2] == "sd" and parts[-1].isdigit():
                        print("depth", parts[-1], file=self.engine)
                    continue

                # A Move (Perhaps)
                if self.board:
                    if parts[0] == "move":
                        movestr = parts[1]
                    # Old Variation
                    elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                        movestr = parts[2]
                    else:
                        movestr = False

                    if movestr:
                        self.waitingForMove = False
                        self.readyForMoveNowCommand = False
                        if self.engineIsInNotPlaying:
                            # If engine was set in pause just before the engine sent its
                            # move, we ignore it. However the engine has to know that we
                            # ignored it, and thus we step it one back
                            log.info(
                                "__parseLine: Discarding engine's move: %s" %
                                movestr,
                                extra={"task": self.defname})
                            print("undo", file=self.engine)
                            continue
                        else:
                            try:
                                move = parseAny(self.board, movestr)
                            except ParsingError:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: ParsingError engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(
                                    WHITEWON if self.board.color == BLACK else
                                    BLACKWON, WON_ADJUDICATION)
                                continue

                            if validate(self.board, move):
                                self.board = None
                                self.queue.put_nowait(move)
                                continue
                            else:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: can't validate engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(
                                    WHITEWON if self.board.color == BLACK else
                                    BLACKWON, WON_ADJUDICATION)
                                continue

                # Analyzing
                if self.engineIsInNotPlaying:
                    if parts[:4] == ["0", "0", "0", "0"]:
                        # Crafty doesn't analyze until it is out of book
                        print("book off", file=self.engine)
                        continue

                    match = anare.match(line)
                    if match:
                        depth, score, time, nodes, moves = match.groups()

                        if "mat" in score.lower() or "#" in moves:
                            # Will look either like -Mat 3 or Mat3
                            scoreval = MATE_VALUE
                            if score.startswith('-'):
                                scoreval = -scoreval
                        else:
                            scoreval = int(score)

                        nps = str(
                            int(int(nodes) /
                                (int(time) / 100))) if int(time) > 0 else ""

                        mvstrs = movere.findall(moves)
                        if mvstrs:
                            self.emit("analyze",
                                      [(self.board.ply, mvstrs, scoreval,
                                        depth.strip(), nps)])

                        continue

                # Offers draw
                if parts[0:2] == ["offer", "draw"]:
                    self.emit("accept", Offer(DRAW_OFFER))
                    continue

                # Resigns
                if parts[0] == "resign" or \
                        (parts[0] == "tellics" and parts[1] == "resign"):  # buggy crafty

                    # Previously: if "resign" in parts,
                    # however, this is too generic, since "hint", "bk",
                    # "feature option=.." and possibly other, future CECPv2
                    # commands can validly contain the word "resign" without this
                    # being an intentional resign offer.

                    self.emit("offer", Offer(RESIGNATION))
                    continue

                # if parts[0].lower() == "error":
                #    continue

                # Tell User Error
                if parts[0] == "tellusererror":
                    # We don't want to see our stop analyzer hack as an error message
                    if "8/8/8/8/8/8/8/8" in "".join(parts[1:]):
                        continue
                    # Create a non-modal non-blocking message dialog with the error:
                    dlg = Gtk.MessageDialog(mainwindow(),
                                            flags=0,
                                            type=Gtk.MessageType.WARNING,
                                            buttons=Gtk.ButtonsType.CLOSE,
                                            message_format=None)

                    # Use the engine name if already known, otherwise the defname:
                    displayname = self.name
                    if not displayname:
                        displayname = self.defname

                    # Compose the dialog text:
                    dlg.set_markup(
                        GObject.markup_escape_text(
                            _("The engine %s reports an error:") %
                            displayname) + "\n\n" +
                        GObject.markup_escape_text(" ".join(parts[1:])))

                    # handle response signal so the "Close" button works:
                    dlg.connect("response", lambda dlg, x: dlg.destroy())

                    dlg.show_all()
                    continue

                # Tell Somebody
                if parts[0][:4] == "tell" and \
                        parts[0][4:] in ("others", "all", "ics", "icsnoalias"):

                    log.info("Ignoring tell %s: %s" %
                             (parts[0][4:], " ".join(parts[1:])))
                    continue

                if "feature" in parts:
                    # Some engines send features after done=1, so we will iterate after done=1 too
                    done1 = False
                    # We skip parts before 'feature', as some engines give us lines like
                    # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
                    parts = parts[parts.index("feature"):]
                    for i, pair in enumerate(parts[1:]):

                        # As "parts" is split with no thoughs on quotes or double quotes
                        # we need to do some extra handling.

                        if pair.find("=") < 0:
                            continue
                        key, value = pair.split("=", 1)

                        if key not in self.features:
                            continue

                        if value.startswith('"') and value.endswith('"'):
                            value = value[1:-1]

                        # If our pair was unfinished, like myname="GNU, we search the
                        # rest of the pairs for a quotating mark.
                        elif value[0] == '"':
                            rest = value[1:] + " " + " ".join(parts[2 + i:])
                            j = rest.find('"')
                            if j == -1:
                                log.warning(
                                    "Missing endquotation in %s feature",
                                    extra={"task": self.defname})
                                value = rest
                            else:
                                value = rest[:j]

                        elif value.isdigit():
                            value = int(value)

                        if key in self.supported_features:
                            print("accepted %s" % key, file=self.engine)
                        else:
                            print("rejected %s" % key, file=self.engine)

                        if key == "done":
                            if value == 1:
                                done1 = True
                                continue
                            elif value == 0:
                                log.info("Adds %d seconds timeout" %
                                         TIME_OUT_SECOND,
                                         extra={"task": self.defname})
                                # This'll buy you some more time
                                self.queue.put_nowait("not ready")
                                break

                        if key == "smp" and value == 1:
                            self.options["cores"] = {
                                "name": "cores",
                                "type": "spin",
                                "default": 1,
                                "min": 1,
                                "max": 64
                            }
                        elif key == "memory" and value == 1:
                            self.options["memory"] = {
                                "name": "memory",
                                "type": "spin",
                                "default": 32,
                                "min": 1,
                                "max": 4096
                            }
                        elif key == "option" and key != "done":
                            option = self.__parse_option(value)
                            self.options[option["name"]] = option
                        else:
                            self.features[key] = value

                        if key == "myname" and not self.name:
                            self.setName(value)

                    if done1:
                        # Start a new game before using the engine:
                        # (CECPv2 engines)
                        print("new", file=self.engine)

                        # We are now ready for play:
                        self.emit("readyForOptions")
                        self.emit("readyForMoves")
                        self.queue.put_nowait("ready")

                # A hack to get better names in protover 1.
                # Unfortunately it wont work for now, as we don't read any lines from
                # protover 1 engines. When should we stop?
                if self.protover == 1:
                    if self.defname[0] in ''.join(parts):
                        basis = self.defname[0]
                        name = ' '.join(
                            itertools.dropwhile(lambda part: basis not in part,
                                                parts))
                        self.features['myname'] = name
                        if not self.name:
                            self.setName(name)
Beispiel #31
0
    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("database",
                                                   perspective_widget)

        self.notebooks = {"gamelist": new_notebook()}
        self.main_notebook = self.notebooks["gamelist"]
        for panel in self.sidePanels:
            self.notebooks[panel.__name__] = new_notebook(panel.__name__)

        self.spinner = Gtk.Spinner()
        self.spinner.set_size_request(50, 50)
        self.progressbar0 = Gtk.ProgressBar(show_text=True)
        self.progressbar1 = Gtk.ProgressBar(show_text=True)

        self.progress_dialog = Gtk.Dialog(
            "", mainwindow(), 0, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
        self.progress_dialog.set_deletable(False)
        self.progress_dialog.get_content_area().pack_start(
            self.spinner, True, True, 0)
        self.progress_dialog.get_content_area().pack_start(
            self.progressbar0, True, True, 0)
        self.progress_dialog.get_content_area().pack_start(
            self.progressbar1, True, True, 0)
        self.progress_dialog.get_content_area().show_all()

        # Initing headbook

        align = createAlignment(4, 4, 0, 4)
        align.set_property("yscale", 0)

        self.headbook = Gtk.Notebook()
        self.headbook.set_name("headbook")
        self.headbook.set_scrollable(True)
        align.add(self.headbook)
        perspective_widget.pack_start(align, False, True, 0)
        self.headbook.connect_after("switch-page", self.on_switch_page)

        # The dock

        self.dock = PyDockTop("database", self)
        align = Gtk.Alignment()
        align.show()
        align.add(self.dock)
        self.dock.show()
        perspective_widget.pack_start(align, True, True, 0)

        self.docks["gamelist"] = (Gtk.Label(label="gamelist"),
                                  self.notebooks["gamelist"], None)
        for panel in self.sidePanels:
            self.docks[panel.__name__][1] = self.notebooks[panel.__name__]

        self.load_from_xml()

        # Default layout of side panels
        if not os.path.isfile(self.dockLocation):
            leaf = self.dock.dock(self.docks["gamelist"][1], CENTER,
                                  self.docks["gamelist"][0], "gamelist")
            leaf.setDockable(False)

            leaf = leaf.dock(self.docks["OpeningTreePanel"][1], EAST,
                             self.docks["OpeningTreePanel"][0],
                             "OpeningTreePanel")
            leaf = leaf.dock(self.docks["FilterPanel"][1], CENTER,
                             self.docks["FilterPanel"][0], "FilterPanel")
            leaf.dock(self.docks["PreviewPanel"][1], SOUTH,
                      self.docks["PreviewPanel"][0], "PreviewPanel")

        def unrealize(dock):
            dock.saveToXML(self.dockLocation)
            dock._del()

        self.dock.connect("unrealize", unrealize)

        self.dock.show_all()
        perspective_widget.show_all()

        perspective_manager.set_perspective_menuitems("database",
                                                      self.menuitems)

        perspective_manager.set_perspective_toolbuttons(
            "database", [self.import_button, self.save_as_button])
Beispiel #32
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", 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 #33
0
 def on_remote_game_activate(self, widget):
     url = getUserTextDialog(mainwindow(), _('Load a remote game'),
                             _('Paste the link to download:'))
     create_task(get_internet_game(url))
Beispiel #34
0
    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("database",
                                                   perspective_widget)

        self.switcher_panel = SwitcherPanel(self)
        self.notebooks["gamelist"] = new_notebook()
        self.notebooks["opening_tree"] = new_notebook()
        self.notebooks["filter"] = new_notebook()
        self.notebooks["preview"] = new_notebook()

        self.spinner = Gtk.Spinner()
        self.spinner.set_size_request(50, 50)
        self.progressbar0 = Gtk.ProgressBar(show_text=True)
        self.progressbar1 = Gtk.ProgressBar(show_text=True)

        self.progress_dialog = Gtk.Dialog(
            "", mainwindow(), 0, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
        self.progress_dialog.get_content_area().pack_start(
            self.spinner, True, True, 0)
        self.progress_dialog.get_content_area().pack_start(
            self.progressbar0, True, True, 0)
        self.progress_dialog.get_content_area().pack_start(
            self.progressbar1, True, True, 0)
        self.progress_dialog.get_content_area().show_all()

        self.dock = PyDockTop("database", self)
        align = Gtk.Alignment()
        align.show()
        align.add(self.dock)
        self.dock.show()
        perspective_widget.pack_start(align, True, True, 0)

        dockLocation = addUserConfigPrefix("pydock-database.xml")

        docks = {
            "gamelist":
            (Gtk.Label(label="gamelist"), self.notebooks["gamelist"]),
            "switcher":
            (dock_panel_tab(_("Databases"), "",
                            addDataPrefix("glade/panel_database.svg")),
             self.switcher_panel.alignment),
            "openingtree":
            (dock_panel_tab(_("Openings"), "",
                            addDataPrefix("glade/panel_book.svg")),
             self.notebooks["opening_tree"]),
            "filter": (dock_panel_tab(_("Filters"), "",
                                      addDataPrefix("glade/panel_filter.svg")),
                       self.notebooks["filter"]),
            "preview": (dock_panel_tab(_("Preview"), "",
                                       addDataPrefix("glade/panel_games.svg")),
                        self.notebooks["preview"]),
        }

        if os.path.isfile(dockLocation):
            try:
                self.dock.loadFromXML(dockLocation, docks)
            except Exception as e:
                stringio = StringIO()
                traceback.print_exc(file=stringio)
                error = stringio.getvalue()
                log.error("Dock loading error: %s\n%s" % (e, error))
                msg_dia = Gtk.MessageDialog(mainwindow(),
                                            type=Gtk.MessageType.ERROR,
                                            buttons=Gtk.ButtonsType.CLOSE)
                msg_dia.set_markup(
                    _("<b><big>PyChess was unable to load your panel settings</big></b>"
                      ))
                msg_dia.format_secondary_text(
                    _("Your panel settings have been reset. If this problem repeats, \
                    you should report it to the developers"))
                msg_dia.run()
                msg_dia.hide()
                os.remove(dockLocation)
                for title, panel in docks.values():
                    title.unparent()
                    panel.unparent()

        if not os.path.isfile(dockLocation):
            leaf = self.dock.dock(docks["gamelist"][1], CENTER,
                                  docks["gamelist"][0], "gamelist")
            leaf.setDockable(False)

            leaf.dock(docks["switcher"][1], NORTH, docks["switcher"][0],
                      "switcher")
            leaf = leaf.dock(docks["openingtree"][1], EAST,
                             docks["openingtree"][0], "openingtree")
            leaf = leaf.dock(docks["filter"][1], CENTER, docks["filter"][0],
                             "filter")
            leaf.dock(docks["preview"][1], SOUTH, docks["preview"][0],
                      "preview")

        def unrealize(dock):
            dock.saveToXML(dockLocation)
            dock._del()

        self.dock.connect("unrealize", unrealize)

        self.dock.show_all()
        perspective_widget.show_all()

        perspective_manager.set_perspective_toolbuttons(
            "database",
            [self.import_button, self.save_as_button, self.close_button])

        self.switcher_panel.connect("chessfile_switched",
                                    self.on_chessfile_switched)
Beispiel #35
0
        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()
Beispiel #36
0
    def generalStart(self, gamemodel, player0tup, player1tup, loaddata=None):
        """ The player tuples are:
        (The type af player in a System.const value,
        A callable creating the player,
        A list of arguments for the callable,
        A preliminary name for the player)

        If loaddata is specified, it should be a tuple of:
        (A text uri or fileobj,
        A Savers.something module with a load function capable of loading it,
        An int of the game in file you want to load,
        The position from where to start the game)
        """

        log.debug("Games.generalStart: %s\n %s\n %s" %
                  (gamemodel, player0tup, player1tup))
        gmwidg = gamewidget.GameWidget(gamemodel, self)
        self.gamewidgets.add(gmwidg)
        self.gmwidg_cids[gmwidg] = gmwidg.connect("game_close_clicked",
                                                  self.closeGame)

        # worker.publish((gmwidg,gamemodel))
        self.attachGameWidget(gmwidg)
        game_nanny.nurseGame(gmwidg, gamemodel)
        log.debug("Games.generalStart: -> emit gmwidg_created: %s" % (gmwidg))
        self.emit("gmwidg_created", gmwidg)
        log.debug("Games.generalStart: <- emit gmwidg_created: %s" % (gmwidg))

        # Initing players

        def xxxset_name(none, player, key, alt):
            player.setName(conf.get(key, alt))

        players = []
        for i, playertup in enumerate((player0tup, player1tup)):
            type, func, args, prename = playertup
            if type != LOCAL:
                if type == ARTIFICIAL:
                    player = yield from func(*args)
                else:
                    player = func(*args)
                players.append(player)
                # if type == ARTIFICIAL:
                #    def readyformoves (player, color):
                #        gmwidg.setTabText(gmwidg.display_text))
                #    players[i].connect("readyForMoves", readyformoves, i)
            else:
                # Until PyChess has a proper profiles system, as discussed on the
                # issue tracker, we need to give human players special treatment
                player = func(gmwidg, *args)
                players.append(player)
        assert len(players) == 2
        if player0tup[0] == ARTIFICIAL and player1tup[0] == ARTIFICIAL:

            def emit_action(board, action, player, param, gmwidg):
                if gmwidg.isInFront():
                    gamemodel.curplayer.emit("offer", Offer(action,
                                                            param=param))

            self.board_cids[gmwidg.board] = gmwidg.board.connect(
                "action", emit_action, gmwidg)

        log.debug("Games.generalStart: -> gamemodel.setPlayers(): %s" %
                  (gamemodel))
        gamemodel.setPlayers(players)
        log.debug("Games.generalStart: <- gamemodel.setPlayers(): %s" %
                  (gamemodel))

        # Forward information from the engines
        for playertup, tagname in ((player0tup, "WhiteElo"), (player1tup,
                                                              "BlackElo")):
            if playertup[0] == ARTIFICIAL:
                elo = playertup[2][0].get("elo")
                if elo:
                    gamemodel.tags[tagname] = elo

        # Starting
        if loaddata:
            try:
                uri, loader, gameno, position = loaddata
                gamemodel.loadAndStart(uri, loader, gameno, position)
                if position != gamemodel.ply and position != -1:
                    gmwidg.board.view.shown = position
            except LoadingError as e:
                d = Gtk.MessageDialog(mainwindow(),
                                      type=Gtk.MessageType.WARNING,
                                      buttons=Gtk.ButtonsType.OK)
                d.set_markup(_("<big><b>Error loading game</big></b>"))
                d.format_secondary_text(", ".join(str(a) for a in e.args))
                d.show()
                d.destroy()

        else:
            if gamemodel.variant.need_initial_board:
                for player in gamemodel.players:
                    player.setOptionInitialBoard(gamemodel)
            log.debug("Games..generalStart: -> gamemodel.start(): %s" %
                      (gamemodel))
            gamemodel.emit("game_loaded", "")
            gamemodel.start()
            log.debug("Games.generalStart: <- gamemodel.start(): %s" %
                      (gamemodel))

        log.debug("Games.generalStart: returning gmwidg=%s\n gamemodel=%s" %
                  (gmwidg, gamemodel))
Beispiel #37
0
    def closeGame(self, gmwidg):
        log.debug("Games.closeGame")
        response = None
        if not gmwidg.gamemodel.isChanged():
            response = Gtk.ResponseType.OK
        else:
            markup = "<b><big>" + _(
                "Save the current game before you close it?") + "</big></b>"
            if conf.get("autoSave"):
                x = self.saveGamePGN(gmwidg.gamemodel)
                if x:
                    response = Gtk.ResponseType.OK
                else:
                    markup = "<b><big>" + _(
                        "Unable to save to configured file. \
                                            Save the current game before you close it?"
                    ) + "</big></b>"

            if response is None:
                d = Gtk.MessageDialog(mainwindow(),
                                      type=Gtk.MessageType.WARNING)
                d.add_button(_("Close _without Saving"), Gtk.ResponseType.OK)
                d.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
                if gmwidg.gamemodel.uri:
                    d.add_button(Gtk.STOCK_SAVE, Gtk.ResponseType.YES)
                else:
                    d.add_button(Gtk.STOCK_SAVE_AS, Gtk.ResponseType.YES)

                gmwidg.bringToFront()

                d.set_markup(markup)
                d.format_secondary_text(
                    _("It is not possible later to continue the game,\nif you don't save it."
                      ))

                response = d.run()
                d.destroy()

            if response == Gtk.ResponseType.YES:
                # Test if cancel was pressed in the save-file-dialog
                if self.saveGame(gmwidg.gamemodel) != Gtk.ResponseType.ACCEPT:
                    response = Gtk.ResponseType.CANCEL

        if response not in (Gtk.ResponseType.DELETE_EVENT,
                            Gtk.ResponseType.CANCEL):
            if gmwidg.gamemodel.status in UNFINISHED_STATES:
                gmwidg.gamemodel.end(ABORTED, ABORTED_AGREEMENT)

            gmwidg.disconnect(self.gmwidg_cids[gmwidg])
            del self.gmwidg_cids[gmwidg]

            for cid in self.notify_cids[gmwidg]:
                conf.notify_remove(cid)
            del self.notify_cids[gmwidg]

            if gmwidg.board in self.board_cids:
                gmwidg.board.disconnect(self.board_cids[gmwidg.board])
                del self.board_cids[gmwidg.board]

            self.delGameWidget(gmwidg)
            self.gamewidgets.remove(gmwidg)
            gmwidg.gamemodel.terminate()

            db_persp = perspective_manager.get_perspective("database")
            if len(self.gamewidgets) == 0:
                for widget in MENU_ITEMS:
                    if widget in ("copy_pgn", "copy_fen"
                                  ) and db_persp.preview_panel is not None:
                        continue
                    gamewidget.getWidgets()[widget].set_property(
                        'sensitive', False)

        return response
Beispiel #38
0
    def on_drag_received(self, widget, context, x, y, selection, target_type,
                         timestamp):
        if target_type == TARGET_TYPE_URI_LIST:
            NOTPROC, PARTIAL, FULL = range(3)
            status = NOTPROC
            uris = selection.get_uris()
            for uri in uris:
                fn, fext = os.path.splitext(uri.lower())
                b = False

                # Chess position
                if fext == '.fen':
                    b = newGameDialog.loadFileAndRun(uri)

                # Shortcut
                elif fext in ['.url', '.desktop']:
                    # Preconf
                    if fext == '.url':
                        sectname = 'InternetShortcut'
                        typeok = True
                    elif fext == '.desktop':
                        sectname = 'Desktop Entry'
                        typeok = False
                    else:
                        assert (False)

                    # Read the shortcut
                    filename = splitUri(uri)[1]
                    with open(filename, 'r') as file:
                        content = file.read()
                    lines = content.replace("\r", '').split("\n")

                    # Extract the link
                    section = False
                    link = ''
                    for item in lines:
                        # Header
                        if item.startswith('['):
                            if section:
                                break
                            section = item.startswith('[%s]' % sectname)
                        if not section:
                            continue

                        # Item
                        if item.startswith('URL='):
                            link = item[4:]
                        if item.startswith('Type=Link') and fext == '.desktop':
                            typeok = True

                    # Load the link
                    if typeok and link != '':
                        pgn = get_internet_game_as_pgn(link)
                        b = newGameDialog.loadPgnAndRun(pgn)

                # Database
                else:
                    perspective = perspective_manager.get_perspective(
                        "database")
                    perspective.open_chessfile(uri)
                    b = True

                # Update the global status
                if b:
                    if status == NOTPROC:
                        status = FULL
                else:
                    if status != NOTPROC:
                        status = PARTIAL

            # Feedback about the load
            msg = ''
            if status == NOTPROC:
                msg = _(
                    'All the links failed to fetch a relevant chess content.')
                msgtype = Gtk.MessageType.ERROR
            elif status == PARTIAL:
                msg = _('Some links were invalid.')
                msgtype = Gtk.MessageType.WARNING
            if msg != '':
                dlg = Gtk.MessageDialog(mainwindow(),
                                        type=msgtype,
                                        buttons=Gtk.ButtonsType.OK,
                                        message_format=msg)
                dlg.run()
                dlg.destroy()
Beispiel #39
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 #40
0
    def saveGameAs(self, game, position=None, export=False):
        savedialog, savecombo = get_save_dialog(export)

        # Keep running the dialog until the user has canceled it or made an error
        # free operation
        title = _("Save Game") if not export else _("Export position")
        savedialog.set_title(title)
        while True:
            savedialog.set_current_name(
                "%s %s %s" % (game.players[0], _("vs."), game.players[1]))

            res = savedialog.run()
            if res != Gtk.ResponseType.ACCEPT:
                break

            uri = savedialog.get_filename()
            ending = os.path.splitext(uri)[1]
            if ending.startswith("."):
                ending = ending[1:]
            append = False

            index = savecombo.get_active()
            if index == 0:
                if ending not in enddir:
                    d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                          buttons=Gtk.ButtonsType.OK)
                    folder, file = os.path.split(uri)
                    d.set_markup(_("<big><b>Unknown file type '%s'</b></big>") %
                                 ending)
                    d.format_secondary_text(_(
                        "Was unable to save '%(uri)s' as PyChess doesn't know the format '%(ending)s'.") %
                        {'uri': uri, 'ending': ending})
                    d.run()
                    d.destroy()
                    continue
                else:
                    saver = enddir[ending]
            else:
                format = exportformats[index] if export else saveformats[index]
                saver = format[2]
                if ending not in enddir or not saver == enddir[ending]:
                    uri += ".%s" % saver.__ending__

            if os.path.isfile(uri) and not os.access(uri, os.W_OK):
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR,
                                      buttons=Gtk.ButtonsType.OK)
                d.set_markup(_("<big><b>Unable to save file '%s'</b></big>") % uri)
                d.format_secondary_text(_(
                    "You don't have the necessary rights to save the file.\n\
    Please ensure that you have given the right path and try again."))
                d.run()
                d.destroy()
                continue

            if os.path.isfile(uri):
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.QUESTION)
                d.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                              _("_Replace"), Gtk.ResponseType.ACCEPT)
                if saver.__append__:
                    d.add_buttons(Gtk.STOCK_ADD, 1)
                d.set_title(_("File exists"))
                folder, file = os.path.split(uri)
                d.set_markup(_(
                    "<big><b>A file named '%s' already exists. Would you like to replace it?</b></big>") % file)
                d.format_secondary_text(_(
                    "The file already exists in '%s'. If you replace it, its content will be overwritten.") % folder)
                replaceRes = d.run()
                d.destroy()

                if replaceRes == 1:
                    append = True
                elif replaceRes == Gtk.ResponseType.CANCEL:
                    continue
            else:
                print(repr(uri))

            try:
                game.save(uri, saver, append, position)
            except IOError as e:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR)
                d.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK)
                d.set_title(_("Could not save the file"))
                d.set_markup(_(
                    "<big><b>PyChess was not able to save the game</b></big>"))
                d.format_secondary_text(_("The error was: %s") % ", ".join(
                    str(a) for a in e.args))
                d.run()
                d.destroy()
                continue

            break

        savedialog.destroy()
        return res
Beispiel #41
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 #42
0
    def generalStart(self, gamemodel, player0tup, player1tup, loaddata=None):
        """ The player tuples are:
        (The type af player in a System.const value,
        A callable creating the player,
        A list of arguments for the callable,
        A preliminary name for the player)

        If loaddata is specified, it should be a tuple of:
        (A text uri or fileobj,
        A Savers.something module with a load function capable of loading it,
        An int of the game in file you want to load,
        The position from where to start the game)
        """

        log.debug("Games.generalStart: %s\n %s\n %s" %
                  (gamemodel, player0tup, player1tup))
        gmwidg = gamewidget.GameWidget(gamemodel, self)
        self.gamewidgets.add(gmwidg)
        self.gmwidg_cids[gmwidg] = gmwidg.connect("game_close_clicked", self.closeGame)

        # worker.publish((gmwidg,gamemodel))
        self.attachGameWidget(gmwidg)
        game_nanny.nurseGame(gmwidg, gamemodel)
        log.debug("Games.generalStart: -> emit gmwidg_created: %s" % (gmwidg))
        self.emit("gmwidg_created", gmwidg)
        log.debug("Games.generalStart: <- emit gmwidg_created: %s" % (gmwidg))

        # Initing players

        def xxxset_name(none, player, key, alt):
            player.setName(conf.get(key, alt))

        players = []
        for i, playertup in enumerate((player0tup, player1tup)):
            type, func, args, prename = playertup
            if type != LOCAL:
                if type == ARTIFICIAL:
                    player = yield from func(*args)
                else:
                    player = func(*args)
                players.append(player)
                # if type == ARTIFICIAL:
                #    def readyformoves (player, color):
                #        gmwidg.setTabText(gmwidg.display_text))
                #    players[i].connect("readyForMoves", readyformoves, i)
            else:
                # Until PyChess has a proper profiles system, as discussed on the
                # issue tracker, we need to give human players special treatment
                player = func(gmwidg, *args)
                players.append(player)
        assert len(players) == 2
        if player0tup[0] == ARTIFICIAL and player1tup[0] == ARTIFICIAL:

            def emit_action(board, action, player, param, gmwidg):
                if gmwidg.isInFront():
                    gamemodel.curplayer.emit("offer", Offer(action, param=param))

            self.board_cids[gmwidg.board] = gmwidg.board.connect("action", emit_action, gmwidg)

        log.debug("Games.generalStart: -> gamemodel.setPlayers(): %s" %
                  (gamemodel))
        gamemodel.setPlayers(players)
        log.debug("Games.generalStart: <- gamemodel.setPlayers(): %s" %
                  (gamemodel))

        # Forward information from the engines
        for playertup, tagname in ((player0tup, "WhiteElo"), (player1tup, "BlackElo")):
            if playertup[0] == ARTIFICIAL:
                elo = playertup[2][0].get("elo")
                if elo:
                    gamemodel.tags[tagname] = elo

        # Starting
        if loaddata:
            try:
                uri, loader, gameno, position = loaddata
                gamemodel.loadAndStart(uri, loader, gameno, position)
                if position != gamemodel.ply and position != -1:
                    gmwidg.board.view.shown = position
            except LoadingError as e:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                                      buttons=Gtk.ButtonsType.OK)
                d.set_markup(_("<big><b>Error loading game</big></b>"))
                d.format_secondary_text(", ".join(str(a) for a in e.args))
                d.show()
                d.destroy()

        else:
            if gamemodel.variant.need_initial_board:
                for player in gamemodel.players:
                    player.setOptionInitialBoard(gamemodel)
            log.debug("Games..generalStart: -> gamemodel.start(): %s" %
                      (gamemodel))

            gamemodel.start()
            log.debug("Games.generalStart: <- gamemodel.start(): %s" %
                      (gamemodel))

        log.debug("Games.generalStart: returning gmwidg=%s\n gamemodel=%s" %
                  (gmwidg, gamemodel))
Beispiel #43
0
    def __init__(self, persp):
        GObject.GObject.__init__(self)
        self.persp = persp
        self.filtered = False
        self.widgets = uistuff.GladeWidgets("PyChess.glade")

        # Build variant combo model
        variant_store = Gtk.ListStore(str, int)

        for name, variant in sorted(name2variant.items()):
            variant_store.append((name, variant.variant))

        self.widgets["variant"].set_model(variant_store)
        renderer_text = Gtk.CellRendererText()
        self.widgets["variant"].pack_start(renderer_text, True)
        self.widgets["variant"].add_attribute(renderer_text, "text", 0)

        # Add piece widgets to dialog *_dock containers on material tab
        self.dialog = self.widgets["filter_dialog"]
        self.dialog.set_transient_for(mainwindow())

        for piece in "qrbnp":
            dock = "w%s_dock" % piece
            self.widgets[dock].add(PieceWidget(Piece(WHITE, chr2Sign[piece])))
            self.widgets[dock].get_child().show()

            dock = "b%s_dock" % piece
            self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece])))
            self.widgets[dock].get_child().show()

            dock = "moved_%s_dock" % piece
            self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece])))
            self.widgets[dock].get_child().show()

            dock = "captured_%s_dock" % piece
            self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece])))
            self.widgets[dock].get_child().show()

        piece = "k"
        dock = "moved_%s_dock" % piece
        self.widgets[dock].add(PieceWidget(Piece(BLACK, chr2Sign[piece])))
        self.widgets[dock].get_child().show()

        # We will store our filtering queries in a ListStore
        # column 0: query as text
        # column 1: query dict
        # column 2: filter type (NONE, TAG_FILTER or MATERIAL_FILTER or PATTERN_FILTER)
        # column 3: row type (RULE, SEQUENCE, STREAK)
        self.treestore = Gtk.TreeStore(str, object, int, int)

        self.set_model(self.treestore)

        self.set_headers_visible(True)
        self.set_grid_lines(Gtk.TreeViewGridLines.HORIZONTAL)

        column = Gtk.TreeViewColumn("filter", Gtk.CellRendererText(), text=0)
        column.set_min_width(80)
        self.append_column(column)

        self.columns_autosize()

        sw = Gtk.ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        sw.add(self)

        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.box.pack_start(sw, True, True, 0)

        # Add buttons
        toolbar = Gtk.Toolbar()

        editButton = Gtk.ToolButton(Gtk.STOCK_EDIT)
        editButton.set_tooltip_text(_("Edit selected filter"))
        editButton.connect("clicked", self.on_edit_clicked)
        toolbar.insert(editButton, -1)

        delButton = Gtk.ToolButton(Gtk.STOCK_REMOVE)
        delButton.set_tooltip_text(_("Remove selected filter"))
        delButton.connect("clicked", self.on_del_clicked)
        toolbar.insert(delButton, -1)

        addButton = Gtk.ToolButton(Gtk.STOCK_ADD)
        addButton.set_tooltip_text(_("Add new filter"))
        addButton.connect("clicked", self.on_add_clicked)
        toolbar.insert(addButton, -1)

        addSeqButton = Gtk.ToolButton()
        addSeqButton.set_label(_("Seq"))
        addSeqButton.set_is_important(True)
        addSeqButton.set_tooltip_text(
            _("Create new squence where listed conditions may be satisfied at different times in a game"
              ))
        addSeqButton.connect("clicked", self.on_add_sequence_clicked)
        toolbar.insert(addSeqButton, -1)

        addStreakButton = Gtk.ToolButton()
        addStreakButton.set_label(_("Str"))
        addStreakButton.set_is_important(True)
        addStreakButton.set_tooltip_text(
            _("Create new streak sequence where listed conditions have to be satisfied in consecutive (half)moves"
              ))
        addStreakButton.connect("clicked", self.on_add_streak_clicked)
        toolbar.insert(addStreakButton, -1)

        self.filterButton = Gtk.ToggleToolButton(Gtk.STOCK_FIND)
        self.filterButton.set_tooltip_text(
            _("Filter game list by various conditions"))
        self.filterButton.connect("clicked", self.on_filter_clicked)
        toolbar.insert(self.filterButton, -1)

        tool_box = Gtk.Box()
        tool_box.pack_start(toolbar, False, False, 0)
        self.box.pack_start(tool_box, False, False, 0)

        self.box.show_all()
Beispiel #44
0
    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("games", perspective_widget)

        self.notebooks = {"board": cleanNotebook("board"),
                          "buttons": cleanNotebook("buttons"),
                          "messageArea": cleanNotebook("messageArea")}
        for panel in sidePanels:
            self.notebooks[panel.__name__] = cleanNotebook(panel.__name__)

        # Initing headbook

        align = gamewidget.createAlignment(4, 4, 0, 4)
        align.set_property("yscale", 0)

        headbook = Gtk.Notebook()
        headbook.set_name("headbook")
        headbook.set_scrollable(True)
        align.add(headbook)
        perspective_widget.pack_start(align, False, True, 0)
        self.show_tabs(not conf.get("hideTabs", False))

        # Initing center

        centerVBox = Gtk.VBox()

        # The dock

        self.dock = PyDockTop("main", self)
        self.dockAlign = gamewidget.createAlignment(4, 4, 0, 4)
        self.dockAlign.add(self.dock)
        centerVBox.pack_start(self.dockAlign, True, True, 0)
        self.dockAlign.show()
        self.dock.show()

        self.docks = {"board": (Gtk.Label(label="Board"), self.notebooks["board"])}
        for panel in sidePanels:
            box = dock_panel_tab(panel.__title__, panel.__desc__, panel.__icon__)
            self.docks[panel.__name__] = (box, self.notebooks[panel.__name__])

        if os.path.isfile(dockLocation):
            try:
                self.dock.loadFromXML(dockLocation, self.docks)
            except Exception as e:
                stringio = StringIO()
                traceback.print_exc(file=stringio)
                error = stringio.getvalue()
                log.error("Dock loading error: %s\n%s" % (e, error))
                msg_dia = Gtk.MessageDialog(mainwindow(),
                                            type=Gtk.MessageType.ERROR,
                                            buttons=Gtk.ButtonsType.CLOSE)
                msg_dia.set_markup(_(
                    "<b><big>PyChess was unable to load your panel settings</big></b>"))
                msg_dia.format_secondary_text(_(
                    "Your panel settings have been reset. If this problem repeats, \
                    you should report it to the developers"))
                msg_dia.run()
                msg_dia.hide()
                os.remove(dockLocation)
                for title, panel in self.docks.values():
                    title.unparent()
                    panel.unparent()

        if not os.path.isfile(dockLocation):
            leaf = self.dock.dock(self.docks["board"][1],
                                  CENTER,
                                  Gtk.Label(label=self.docks["board"][0]),
                                  "board")
            self.docks["board"][1].show_all()
            leaf.setDockable(False)

            # S
            epanel = leaf.dock(self.docks["bookPanel"][1], SOUTH, self.docks["bookPanel"][0],
                               "bookPanel")
            epanel.default_item_height = 45
            epanel = epanel.dock(self.docks["engineOutputPanel"][1], CENTER,
                                 self.docks["engineOutputPanel"][0],
                                 "engineOutputPanel")

            # NE
            leaf = leaf.dock(self.docks["annotationPanel"][1], EAST,
                             self.docks["annotationPanel"][0], "annotationPanel")
            leaf = leaf.dock(self.docks["historyPanel"][1], CENTER,
                             self.docks["historyPanel"][0], "historyPanel")
            leaf = leaf.dock(self.docks["scorePanel"][1], CENTER,
                             self.docks["scorePanel"][0], "scorePanel")

            # SE
            leaf = leaf.dock(self.docks["chatPanel"][1], SOUTH, self.docks["chatPanel"][0],
                             "chatPanel")
            leaf = leaf.dock(self.docks["commentPanel"][1], CENTER,
                             self.docks["commentPanel"][0], "commentPanel")

        def unrealize(dock, notebooks):
            # unhide the panel before saving so its configuration is saved correctly
            self.notebooks["board"].get_parent().get_parent().zoomDown()
            dock.saveToXML(dockLocation)
            dock._del()

        self.dock.connect("unrealize", unrealize, self.notebooks)

        hbox = Gtk.HBox()

        # Buttons
        self.notebooks["buttons"].set_border_width(4)
        hbox.pack_start(self.notebooks["buttons"], False, True, 0)

        # The message area
        # TODO: If you try to fix this first read issue #958 and 1018
        align = gamewidget.createAlignment(0, 0, 0, 0)
        # sw = Gtk.ScrolledWindow()
        # port = Gtk.Viewport()
        # port.add(self.notebooks["messageArea"])
        # sw.add(port)
        # align.add(sw)
        align.add(self.notebooks["messageArea"])
        hbox.pack_start(align, True, True, 0)

        def ma_switch_page(notebook, gpointer, page_num):
            notebook.props.visible = notebook.get_nth_page(page_num).\
                get_child().props.visible

        self.notebooks["messageArea"].connect("switch-page", ma_switch_page)
        centerVBox.pack_start(hbox, False, True, 0)

        perspective_widget.pack_start(centerVBox, True, True, 0)
        centerVBox.show_all()
        perspective_widget.show_all()

        conf.notify_add("hideTabs", self.tabsCallback)

        # Connecting headbook to other notebooks

        def hb_switch_page(notebook, gpointer, page_num):
            for notebook in self.notebooks.values():
                notebook.set_current_page(page_num)

            gmwidg = self.key2gmwidg[self.getheadbook().get_nth_page(page_num)]
            if isinstance(gmwidg.gamemodel, ICGameModel):
                primary = "primary " + str(gmwidg.gamemodel.ficsgame.gameno)
                gmwidg.gamemodel.connection.client.run_command(primary)

        headbook.connect("switch-page", hb_switch_page)

        if hasattr(headbook, "set_tab_reorderable"):

            def page_reordered(widget, child, new_num, headbook):
                old_num = self.notebooks["board"].page_num(self.key2gmwidg[child].boardvbox)
                if old_num == -1:
                    log.error('Games and labels are out of sync!')
                else:
                    for notebook in self.notebooks.values():
                        notebook.reorder_child(
                            notebook.get_nth_page(old_num), new_num)

            headbook.connect("page-reordered", page_reordered, headbook)
Beispiel #45
0
    def closeGame(self, gmwidg):
        log.debug("Games.closeGame")
        response = None
        if not gmwidg.gamemodel.isChanged():
            response = Gtk.ResponseType.OK
        else:
            markup = "<b><big>" + _("Save the current game before you close it?") + "</big></b>"
            if conf.get("autoSave"):
                x = self.saveGamePGN(gmwidg.gamemodel)
                if x:
                    response = Gtk.ResponseType.OK
                else:
                    markup = "<b><big>" + _("Unable to save to configured file. \
                                            Save the current game before you close it?") + "</big></b>"

            if response is None:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING)
                d.add_button(_("Close _without Saving"), Gtk.ResponseType.OK)
                d.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
                if gmwidg.gamemodel.uri:
                    d.add_button(Gtk.STOCK_SAVE, Gtk.ResponseType.YES)
                else:
                    d.add_button(Gtk.STOCK_SAVE_AS, Gtk.ResponseType.YES)

                gmwidg.bringToFront()

                d.set_markup(markup)
                d.format_secondary_text(_(
                    "It is not possible later to continue the game,\nif you don't save it."))

                response = d.run()
                d.destroy()

            if response == Gtk.ResponseType.YES:
                # Test if cancel was pressed in the save-file-dialog
                if self.saveGame(gmwidg.gamemodel) != Gtk.ResponseType.ACCEPT:
                    response = Gtk.ResponseType.CANCEL

        if response not in (Gtk.ResponseType.DELETE_EVENT,
                            Gtk.ResponseType.CANCEL):
            if gmwidg.gamemodel.status in UNFINISHED_STATES:
                gmwidg.gamemodel.end(ABORTED, ABORTED_AGREEMENT)

            gmwidg.disconnect(self.gmwidg_cids[gmwidg])
            del self.gmwidg_cids[gmwidg]

            for cid in self.notify_cids[gmwidg]:
                conf.notify_remove(cid)
            del self.notify_cids[gmwidg]

            if gmwidg.board in self.board_cids:
                gmwidg.board.disconnect(self.board_cids[gmwidg.board])
                del self.board_cids[gmwidg.board]

            self.delGameWidget(gmwidg)
            self.gamewidgets.remove(gmwidg)
            gmwidg.gamemodel.terminate()

            db_persp = perspective_manager.get_perspective("database")
            if len(self.gamewidgets) == 0:
                for widget in MENU_ITEMS:
                    if widget in ("copy_pgn", "copy_fen") and db_persp.preview_panel is not None:
                        continue
                    gamewidget.getWidgets()[widget].set_property('sensitive', False)

        return response
Beispiel #46
0
    def __init__(self, lounge):
        self.lounge = lounge
        self.widgets = lounge.widgets
        self.connection = lounge.connection

        self.widgets["editSeekDialog"].set_transient_for(mainwindow())
        self.widgets["challengeDialog"].set_transient_for(mainwindow())

        self.finger = None
        conf.set("numberOfFingers", 0)
        self.connection.fm.connect("fingeringFinished", self.onFinger)
        self.connection.fm.finger(self.connection.getUsername())

        self.widgets["untimedCheck"].connect("toggled",
                                             self.onUntimedCheckToggled)
        self.widgets["minutesSpin"].connect("value-changed",
                                            self.onTimeSpinChanged)
        self.widgets["gainSpin"].connect("value-changed",
                                         self.onTimeSpinChanged)
        self.onTimeSpinChanged(self.widgets["minutesSpin"])

        self.widgets["nocolorRadio"].connect("toggled",
                                             self.onColorRadioChanged)
        self.widgets["whitecolorRadio"].connect("toggled",
                                                self.onColorRadioChanged)
        self.widgets["blackcolorRadio"].connect("toggled",
                                                self.onColorRadioChanged)
        self.onColorRadioChanged(self.widgets["nocolorRadio"])

        self.widgets["noVariantRadio"].connect("toggled",
                                               self.onVariantRadioChanged)
        self.widgets["variantRadio"].connect("toggled",
                                             self.onVariantRadioChanged)
        variantcombo = self.widgets["variantCombo"]
        variantcombo.set_name("variantcombo")
        variantComboGetter, variantComboSetter = self.__initVariantCombo(
            variantcombo)
        self.seekEditorWidgetGettersSetters["variantCombo"] = (
            variantComboGetter, variantComboSetter)
        self.widgets["variantCombo"].connect("changed",
                                             self.onVariantComboChanged)

        self.widgets["editSeekDialog"].connect("delete_event", lambda *a: True)
        #        self.widgets["challengeDialog"].connect("delete_event", lambda *a: True)

        self.widgets["strengthCheck"].connect("toggled",
                                              self.onStrengthCheckToggled)
        self.onStrengthCheckToggled(self.widgets["strengthCheck"])
        self.widgets["ratingCenterSlider"].connect(
            "value-changed", self.onRatingCenterSliderChanged)
        self.onRatingCenterSliderChanged(self.widgets["ratingCenterSlider"])
        self.widgets["toleranceSlider"].connect("value-changed",
                                                self.onToleranceSliderChanged)
        self.onToleranceSliderChanged(self.widgets["toleranceSlider"])
        self.widgets["toleranceButton"].connect("clicked",
                                                self.onToleranceButtonClicked)
        self.widgets["toleranceButton"].connect("activate-link",
                                                lambda link_button: True)

        def intGetter(widget):
            return int(widget.get_value())

        self.seekEditorWidgetGettersSetters["minutesSpin"] = (intGetter, None)
        self.seekEditorWidgetGettersSetters["gainSpin"] = (intGetter, None)
        self.seekEditorWidgetGettersSetters["ratingCenterSlider"] = \
            (intGetter, None)
        self.seekEditorWidgetGettersSetters["toleranceSlider"] = \
            (intGetter, None)

        def toleranceHBoxGetter(widget):
            return self.widgets["toleranceHBox"].get_property("visible")

        def toleranceHBoxSetter(widget, visible):
            assert isinstance(visible, bool)
            if visible:
                self.widgets["toleranceHBox"].show()
            else:
                self.widgets["toleranceHBox"].hide()

        self.seekEditorWidgetGettersSetters["toleranceHBox"] = (
            toleranceHBoxGetter, toleranceHBoxSetter)

        self.chainbox = ChainVBox()
        self.widgets["chainAlignment"].add(self.chainbox)

        def chainboxGetter(widget):
            return self.chainbox.active

        def chainboxSetter(widget, is_active):
            self.chainbox.active = is_active

        self.seekEditorWidgetGettersSetters["chainAlignment"] = (
            chainboxGetter, chainboxSetter)

        self.challengee = None
        self.in_challenge_mode = False
        self.seeknumber = 1
        self.widgets["seekButton"].connect("clicked", self.onSeekButtonClicked)
        self.widgets["seekAllButton"].connect("clicked",
                                              self.onSeekAllButtonClicked)
        self.widgets["challengeButton"].connect("clicked",
                                                self.onChallengeButtonClicked)
        self.widgets["challengeDialog"].connect("delete-event",
                                                self.onChallengeDialogResponse)
        self.widgets["challengeDialog"].connect("response",
                                                self.onChallengeDialogResponse)
        self.widgets["editSeekDialog"].connect("response",
                                               self.onEditSeekDialogResponse)

        for widget in ("seek1Radio", "seek2Radio", "seek3Radio",
                       "challenge1Radio", "challenge2Radio",
                       "challenge3Radio"):
            uistuff.keep(self.widgets[widget], widget)

        self.lastdifference = 0
        self.loading_seek_editor = False
        self.savedSeekRadioTexts = [GAME_TYPES["blitz"].display_text] * 3

        for i in range(1, 4):
            self.__loadSeekEditor(i)
            self.__writeSavedSeeks(i)
            self.widgets["seek%sRadioConfigButton" % i].connect(
                "clicked", self.onSeekRadioConfigButtonClicked, i)
            self.widgets["challenge%sRadioConfigButton" % i].connect(
                "clicked", self.onChallengeRadioConfigButtonClicked, i)

        if not self.connection.isRegistred():
            self.chainbox.active = False
            self.widgets["chainAlignment"].set_sensitive(False)
            self.widgets["chainAlignment"].set_tooltip_text(
                _("The chain button is disabled because you are logged in as a guest. Guests \
                can't establish ratings, and the chain button's state has no effect when \
                there is no rating to which to tie \"Opponent Strength\" to"))
Beispiel #47
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 #48
0
        def onResponse(dialog, response):
            if response == COPY:
                clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
                clipboard.set_text(cls.get_fen(), -1)
                # print("put clipboard:", clipboard.wait_for_text())
                return
            elif response == CLEAR:
                cls.board_control.emit("action", "SETUP", None, True)
                cls.ini_widgets(True)
                # print("clear")
                return
            elif response == PASTE:
                clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
                text = clipboard.wait_for_text()
                # print("got clipboard:", text)
                if text is None or len(text.split()) < 2:
                    return
                try:
                    lboard = cls.setupmodel.variant(setup=text).board
                    cls.ini_widgets(lboard.asFen())
                    cls.board_control.emit("action", "SETUP", None, text)
                except SyntaxError as e:
                    d = Gtk.MessageDialog(mainwindow(),
                                          type=Gtk.MessageType.WARNING,
                                          buttons=Gtk.ButtonsType.OK,
                                          message_format=e.args[0])
                    if len(e.args) > 1:
                        d.format_secondary_text(e.args[1])
                    d.connect("response", lambda d, a: d.hide())
                    d.show()
                return
            elif response == INITIAL:
                lboard = cls.setupmodel.variant(setup=FEN_START).board
                cls.ini_widgets(lboard.asFen())
                cls.board_control.emit("action", "SETUP", None, FEN_START)
                return
            elif response != Gtk.ResponseType.OK:
                cls.widgets["newgamedialog"].hide()
                cls.widgets["newgamedialog"].disconnect(handlerId)
                return

            if hasattr(cls, "board_control"):
                cls.board_control.emit("action", "CLOSE", None, None)

            # Find variant
            if cls.widgets["playNormalRadio"].get_active():
                variant_index = NORMALCHESS
            elif cls.widgets["playVariant1Radio"].get_active():
                variant_index = conf.get("ngvariant1")
            else:
                variant_index = conf.get("ngvariant2")
            variant = variants[variant_index]

            # Find time
            if cls.widgets["notimeRadio"].get_active():
                secs = 0
                incr = 0
                moves = 0
            elif cls.widgets["blitzRadio"].get_active():
                secs = cls.ngblitz_min.get_value_as_int() * 60
                incr = cls.ngblitz_gain.get_value_as_int()
                moves = 0
            elif cls.widgets["rapidRadio"].get_active():
                secs = cls.ngrapid_min.get_value_as_int() * 60
                incr = cls.ngrapid_gain.get_value_as_int()
                moves = 0
            elif cls.widgets["normalRadio"].get_active():
                secs = cls.ngnormal_min.get_value_as_int() * 60
                incr = cls.ngnormal_gain.get_value_as_int()
                moves = 0
            elif cls.widgets["classicalRadio"].get_active():
                secs = cls.ngclassical_min.get_value_as_int() * 60
                incr = 0
                moves = cls.ngclassical_moves.get_value_as_int()

            # Find players
            player0combo = cls.widgets["whitePlayerCombobox"]
            player0 = player0combo.get_active()

            tree_iter = player0combo.get_active_iter()
            if tree_iter is not None:
                model = player0combo.get_model()
                name0 = model[tree_iter][1]

            diffi0 = int(cls.widgets["skillSlider1"].get_value())

            player1combo = cls.widgets["blackPlayerCombobox"]
            player1 = player1combo.get_active()

            tree_iter = player1combo.get_active_iter()
            if tree_iter is not None:
                model = player1combo.get_model()
                name1 = model[tree_iter][1]

            diffi1 = int(cls.widgets["skillSlider2"].get_value())

            # Prepare players
            playertups = []
            for i, playerno, name, diffi, color in ((0, player0, name0, diffi0,
                                                     WHITE),
                                                    (1, player1, name1, diffi1,
                                                     BLACK)):
                if playerno > 0:
                    engine = discoverer.getEngineByName(name)
                    playertups.append(
                        (ARTIFICIAL, discoverer.initPlayerEngine,
                         [engine, color, diffi, variant, secs, incr,
                          moves], name))
                else:
                    if not playertups or playertups[0][0] != LOCAL:
                        name = conf.get("firstName")
                    else:
                        name = conf.get("secondName")
                    playertups.append((LOCAL, Human, (color, name), name))

            # Set forcePonderOff initPlayerEngine param True in engine-engine games
            if playertups[0][0] == ARTIFICIAL and playertups[1][
                    0] == ARTIFICIAL:
                playertups[0][2].append(True)
                playertups[1][2].append(True)

            timemodel = TimeModel(secs, incr, moves=moves)
            gamemodel = GameModel(timemodel, variant)

            if not validate(gamemodel):
                return
            else:
                cls.widgets["newgamedialog"].hide()
                cls.widgets["newgamedialog"].disconnect(handlerId)
                callback(gamemodel, playertups[0], playertups[1])
Beispiel #49
0
    def __init__(self):
        self.widgets = uistuff.GladeWidgets("tipoftheday.glade")
        self.widgets["window1"].set_transient_for(mainwindow())
        uistuff.keepWindowSize("tipoftheday", self.widgets["window1"], (320, 240), uistuff.POSITION_CENTER)

        self.widgets["checkbutton1"].set_active(conf.get("show_tip_at_startup"))
        self.widgets["checkbutton1"].connect("toggled", lambda w: conf.set("show_tip_at_startup", w.get_active()))
        self.widgets["close_button"].connect("clicked", lambda w: self.widgets["window1"].emit("delete-event", None))
        self.widgets["window1"].connect("delete_event", lambda w, a: self.widgets["window1"].destroy())
        self.widgets["back_button"].connect("clicked", lambda w: self.set_currentIndex(self.tips_curindex - 1))
        self.widgets["forward_button"].connect("clicked", lambda w: self.set_currentIndex(self.tips_curindex + 1))

        self.tips_fixed = 2
        self.tips = [
            # PyChess facts -- The first tips_fixed messages are always displayed first
            _("PyChess is an open-source chess application that can be enhanced by any chess enthusiasts: bug reports, source code, documentation, translations, feature requests, user assistance... Let's get in touch at <b>http://www.pychess.org</b>"),
            _("PyChess supports a wide range of chess engines, variants, Internet servers and lessons. It is a perfect desktop application to increase your chess skills very conveniently."),
            _("The releases of PyChess hold the name of historical world chess champions. Do you know the name of the current world chess champion?"),
            _("Do you know that you can help to translate PyChess into your language, <b>Help</b> > <b>Translate PyChess</b>."),
            _("A game is made of an opening, a middle-game and an end-game. PyChess is able to train you thanks to its opening book, its supported chess engines and its training module."),

            # Chess facts
            _("Do you know that it is possible to finish a chess game in just 2 turns?"),
            _("Do you know that a knight is better placed in the center of the board?"),
            _("Do you know that moving the queen at the very beginning of a game does not offer any particular advantage?"),
            _("Do you know that having two-colored bishops working together is very powerful?"),
            _("Do you know that the rooks are generally engaged late in game?"),
            _("Do you know that the king can move across two cells under certain conditions? This is called ""castling""."),
            _("Do you know that the number of possible chess games exceeds the number of atoms in the Universe?"),

            # General UI
            _("You can start a new game by <b>Game</b> > <b>New Game</b>, then choose the <b>Players</b>, <b>Time Control</b> and <b>Chess Variants</b>."),
            _("You can choose from 20 different difficulties to play against the computer. It will mainly affect the available time to think."),
            _("The level 20 gives a full autonomy to the chess engine in managing its own time during the game."),
            _("To save a game <b>Game</b> > <b>Save Game As</b>, give the filename and choose where you want to be saved. At the bottom choose extension type of the file, and <b>Save</b>."),
            _("Calling the flag is the termination of the current game when the time of your opponent is over. If the clock is with you, click on the menu item <b>Actions</b> > <b>Call Flag</b> to claim the victory."),
            _("Press <b>Ctrl+Z</b> to ask your opponent to rollback the last played move. Against a computer or for an unrated game, undoing is generally automatically accepted."),
            _("To play on <b>Fullscreen mode</b>, just press the key <b>F11</b>. Press it again to exit this mode."),
            _("Many sounds are emitted by PyChess while you are playing if you activate them in the preferences: <b>Settings</b> > <b>Preferences</b> > <b>Sound tab</b> > <b>Use sounds in PyChess</b>."),
            _("Do you know that a game is generally finished after 20 to 40 moves per player? The estimated duration of a game is displayed when you configure a new game."),
            _("The standard file format to manage chess games is <b>PGN</b>. It stands for ""Portable Game Notation"". Do not get confused with PNG which is a usual file format to store drawings and pictures."),
            _("You can share a position by using the exchange format <b>FEN</b>, which stands for ""Forsyth-Edwards Notation"". This format is also adapted for the chess variants."),

            # Analysis
            _("You must define a chess engine in the preferences in order to use the local chess analysis. By default, PyChess recommends you to use the free engine named Stockfish which is renown to be the strongest engine in the world."),
            _("<b>Hint mode</b> analyzes your game to show you the best current move. Enable it with the shortcut <b>Ctrl+H</b> from the menu <b>View</b>."),
            _("<b>Spy mode</b> analyzes the threats, so the best move that your opponent would play as if it was his turn. Enable it with the shortcut <b>Ctrl+H</b> from the menu <b>View</b>."),
            _("<b>Ponder</b> is an option available in some chess engines that allows thinking when it is not the turn of the engine. It will then consume more resources on your computer."),
            _("<b>MultiPV</b> is an option of some chess engines that shows other possible good moves. They are displayed in the panel <b>Hints</b>. The value can be adapted from that panel with a double-click on the displayed figure."),
            _("You cannot use the local chess analysis mode while you are playing an unterminated game over Internet. Else you would be a cheater."),
            _("An evaluation of +2.3 is an advantage for White of more than 2 pawns, even if White and Black have the same number of pawns. The position of all the pieces and their mobility are some of the factors that contribute to the score."),
            _("PyChess includes a chess engine that offers an evaluation for any chess position. Winning against PyChess engine is a coherent way to succeed in chess and improve your skills."),
            _("The rating is your strength: 1500 is a good average player, 2000 is a national champion and 2800 is the best human chess champion. From the properties of the game in the menu <b>Game</b>, the difference of points gives you your chance to win and the projected evolution of your rating. If your rating is provisional, append a question mark '?' to your level, like ""1399?""."),
            _("Several rating systems exist to evaluate your skills in chess. The most common one is ELO (from its creator Arpad Elo) established on 1970. Schematically, the concept is to engage +/- 20 points for a game and that you will win or lose proportionally to the difference of ELO points you have with your opponent."),
            _("Each chess engine has its own evaluation function. It is normal to get different scores for a same position."),

            # Opening book and EGDB
            _("The opening book gives you the moves that are considered to be good from a theoretical perspective. You are free to play any other legal move."),
            _("The <b>Gaviota tables</b> are precalculated positions that tell the final outcome of the current game in terms of win, loss or draw."),
            _("Do you know that your computer is too small to store a 7-piece endgame database? That's why the Gaviota tablebase is limited to 5 pieces."),
            _("A tablebase can be connected either to PyChess, or to a compatible chess engine."),
            _("The <b>DTZ</b> is the ""distance to zero"", so the remaining possible moves to end into a tie as soon as possible."),

            # Variant chess
            _("The chess variants consist in changing the start position, the rules of the game, the types of the pieces... The gameplay is totally modified, so you must use dedicated chess engines to play against the computer."),
            _("In Chess960, the lines of the main pieces are shuffled in a precise order. Therefore, you cannot use the booking book and you should change your tactical habits."),
            _("When playing crazyhouse chess, the captured pieces change of ownership and can reappear on the board at a later turn."),
            _("Suicide chess, giveaway chess or antichess are all the same variant: you must give your pieces to your opponent by forcing the captures like at draughts. The outcome of the game can change completely if you make an incorrect move."),
            _("Playing horde in PyChess consists in destroying a flow of 36 white pawns with a normal set of black pieces."),
            _("You might be interested in playing ""King of the hill"" if you target to place your king in the middle of the board, instead of protecting it in a corner of the board as usual."),
            _("A lot of fun is offered by atomic chess that destroys all the surrounding main pieces at each capture move."),
            _("The experienced chess players can use blind pieces by starting a new variant game."),

            # Internet chess
            _("You should sign up online to play on an Internet chess server, so that you can find your games later and see the evolution of your rating. In the preferences, PyChess still have the possibility to save your played games locally."),
            _("The time compensation is a feature that doesn't waste your clock time because of the latency of your Internet connection. The module can be downloaded from the menu <b>Edit</b> > <b>Externals</b>."),
            _("You can play against chess engines on an Internet chess server. Use the filter to include or exclude them from the available players."),
            _("The communication with an Internet chess server is not standardized. Therefore you can only connect to the supported chess servers in PyChess, like freechess.org or chessclub.com"),

            # Externals
            _("PyChess uses the external module Scoutfish to evaluate the chess databases. For example, it is possible to extract the games where some pieces are in precise count or positions."),
            _("Parser/ChessDB is an external module used by PyChess to show the expected outcome for a given position."),
            _("SQLite is an internal module used to describe the loaded PGN files, so that PyChess can retrieve the games very fast during a search."),
            _("PyChess generates 3 information files when a PGN file is opened : .sqlite (description), scout (positions), .bin (book and outcomes). These files can be removed manually if necessary."),

            # Lessons
            _("PyChess uses offline lessons to learn chess. You will be then never disappointed if you have no Internet connection."),
            _("To start Learning, click on the <b>Book icon</b> available on the welcome screen. Or choose the category next to that button to start the activity directly."),
            _("The <b>lectures</b> are commented games to learn step-by-step the strategy and principles of some chess techniques. Just watch and read."),
            _("Whatever the number of pawns, an <b>end-game</b> starts when the board is made of certain main pieces : 1 rook vs 1 bishop, 1 queen versus 2 rooks, etc... Knowing the moves will help you to not miss the checkmate!"),
            _("A <b>puzzle</b> is a set of simple positions classified by theme for which you should guess the best moves. It helps you to understand the patterns to drive an accurate attack or defense."),
            _("A <b>lesson</b> is a complex study that explains the tactics for a given position. It is common to view circles and arrows over the board to focus on the behavior of the pieces, the threats, etc...")
        ]
        self.tips_seed = conf.get("tips_seed")
        if self.tips_seed == 0:  # Forbidden value
            self.tips_seed = 123456789 + randrange(876543210)
            conf.set("tips_seed", self.tips_seed)
        self.tips_curindex = conf.get("tips_index")
        self.shuffleTips()
Beispiel #50
0
    def __init__(self, widgets):
        self.widgets = widgets

        # Font chooser
        font = conf.get("movetextFont", "FreeSerif Regular 12")
        font_button = Gtk.FontButton.new_with_font(font)
        demo_text = "♔a1 ♕f8 ♖h8 ♗g7 ♘g2 Ka1 Qf8 Rh8 Bg7 Ng2"
        font_button.set_preview_text(demo_text)
        self.widgets["fontChooserDock"].add(font_button)
        font_button.show()

        def select_font(button):
            conf.set("movetextFont", button.get_font_name())

        font_button.connect("font-set", select_font)

        # Background image
        path = conf.get("welcome_image", addDataPrefix("glade/clear.png"))
        conf.set("welcome_image", path)

        image_chooser_dialog = Gtk.FileChooserDialog(
            _("Select background image file"), mainwindow(),
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        image_chooser_button = Gtk.FileChooserButton.new_with_dialog(
            image_chooser_dialog)

        filter = Gtk.FileFilter()
        filter.set_name(_("Images"))
        filter.add_pattern("*.bmp")
        filter.add_pattern("*.jpg")
        filter.add_pattern("*.png")
        filter.add_pattern("*.svg")
        image_chooser_dialog.add_filter(filter)
        image_chooser_button.set_filename(path)

        self.widgets["imageChooserDock"].add(image_chooser_button)
        image_chooser_button.show()

        def select_new_image(button):
            new_image = image_chooser_dialog.get_filename()
            if new_image:
                conf.set("welcome_image", new_image)
                from pychess.widgets.TaskerManager import tasker
                newTheme(tasker, background=new_image)
                tasker.queue_draw()
            else:
                # restore the original
                image_chooser_dialog.set_filename(path)

        image_chooser_button.connect("file-set", select_new_image)

        # Board style
        uistuff.createCombo(widgets["board_style"], name="board_style")
        data = [(item[0], item[1]) for item in board_items]

        uistuff.createCombo(widgets["board_style"], data)
        uistuff.keep(widgets["board_style"], "board_style", first_value=1)

        # conf.set("board_style", conf.get("board_style", 1))

        # Board frame
        uistuff.createCombo(widgets["board_frame"], name="board_frame")
        data = [(item[0], item[1])
                for item in [(None, "no frame")] + board_items[1:]]

        uistuff.createCombo(widgets["board_frame"], data)
        uistuff.keep(widgets["board_frame"], "board_frame", first_value=1)

        # conf.set("board_frame", conf.get("board_frame", 1))

        # Board Colours

        style_ctxt = widgets["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])

        def onColourSetLight(_):
            """ :Description: Sets the light squares of the chess board
                to the value selected in the colour picker
            """
            conf.set('lightcolour',
                     widgets['light_cbtn'].get_color().to_string())

        widgets["light_cbtn"].connect_after("color-set", onColourSetLight)

        def onColourSetDark(_):
            """ :Description: Sets the dark squares of the chess board
                to the value selected in the colour picker
            """
            conf.set('darkcolour',
                     widgets['dark_cbtn'].get_color().to_string())

        widgets["dark_cbtn"].connect_after("color-set", onColourSetDark)

        def onResetColourClicked(_):
            """ :Description: Resets the chess board squares to factory default
            """
            conf.set("lightcolour", LIGHT)
            conf.set("darkcolour", DARK)

        widgets["reset_btn"].connect("clicked", onResetColourClicked)

        # Get the current board colours if set, if not set, set them to default
        conf.set("lightcolour", conf.get("lightcolour", LIGHT))
        conf.set("darkcolour", conf.get("darkcolour", DARK))

        # Next 2 lines take a #hex str converts them to a color then to a RGBA representation
        self.lightcolour = Gdk.RGBA()
        self.lightcolour.parse(conf.get("lightcolour", LIGHT))
        self.darkcolour = Gdk.RGBA()
        self.darkcolour.parse(conf.get("darkcolour", DARK))

        # Set the color swatches in preference to stored values
        widgets['light_cbtn'].set_rgba(self.lightcolour)
        widgets['dark_cbtn'].set_rgba(self.darkcolour)

        # Chess Sets

        self.themes = self.discoverThemes()
        store = Gtk.ListStore(GdkPixbuf.Pixbuf, str)

        for theme in self.themes:
            pngfile = "%s/%s.png" % (addDataPrefix("pieces"), theme)

            if isfile(pngfile):
                pixbuf = get_pixbuf(pngfile)
                store.append((pixbuf, theme))
            else:
                print(
                    "WARNING: No piece theme preview icons found. Please run \
                    create_theme_preview.sh !")
                break

        self.icon_view = widgets["pieceTheme"]
        self.icon_view.set_model(store)
        self.icon_view.set_pixbuf_column(0)
        self.icon_view.set_text_column(1)

        def keepSize(crt, _):
            """ :Description: Hack to fix spacing problem in iconview
                http://stackoverflow.com/questions/14090094/what-causes-the-different-\
                    display-behaviour-for-a-gtkiconview-between-different
            """
            crt.handler_block(crt_notify)
            crt.set_property('width', 40)
            crt.handler_unblock(crt_notify)

        crt = self.icon_view.get_cells()[0]
        crt_notify = crt.connect('notify', keepSize)

        def _getActive(iconview):
            model = iconview.get_model()
            selected = iconview.get_selected_items()

            if len(selected) == 0:
                return conf.get("pieceTheme", "Chessicons")

            indices = selected[0].get_indices()
            if indices:
                idx = indices[0]
                theme = model[idx][1]
                Pieces.set_piece_theme(theme)
                return theme

        def _setActive(iconview, value):
            try:
                index = self.themes.index(value)
            except ValueError:
                index = 0
            iconview.select_path(Gtk.TreePath(index, ))

        uistuff.keep(widgets["pieceTheme"], "pieceTheme", _getActive,
                     _setActive, "Chessicons")
Beispiel #51
0
        def onResponse(dialog, response):
            if response == COPY:
                clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
                clipboard.set_text(cls.get_fen(), -1)
                # print("put clipboard:", clipboard.wait_for_text())
                return
            elif response == CLEAR:
                cls.board_control.emit("action", "SETUP", None, True)
                cls.ini_widgets(True)
                # print("clear")
                return
            elif response == PASTE:
                clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
                text = clipboard.wait_for_text()
                # print("got clipboard:", text)
                if text is None or len(text.split()) < 2:
                    return
                try:
                    lboard = cls.setupmodel.variant(setup=text).board
                    cls.ini_widgets(lboard.asFen())
                    cls.board_control.emit("action", "SETUP", None, text)
                except SyntaxError as e:
                    d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                                          buttons=Gtk.ButtonsType.OK,
                                          message_format=e.args[0])
                    if len(e.args) > 1:
                        d.format_secondary_text(e.args[1])
                    d.connect("response", lambda d, a: d.hide())
                    d.show()
                return
            elif response == INITIAL:
                lboard = cls.setupmodel.variant(setup=FEN_START).board
                cls.ini_widgets(lboard.asFen())
                cls.board_control.emit("action", "SETUP", None, FEN_START)
                return
            elif response != Gtk.ResponseType.OK:
                cls.widgets["newgamedialog"].hide()
                cls.widgets["newgamedialog"].disconnect(handlerId)
                return

            if hasattr(cls, "board_control"):
                cls.board_control.emit("action", "CLOSE", None, None)

            # Find variant
            if cls.widgets["playNormalRadio"].get_active():
                variant_index = NORMALCHESS
            elif cls.widgets["playVariant1Radio"].get_active():
                variant_index = conf.get("ngvariant1")
            else:
                variant_index = conf.get("ngvariant2")
            variant = variants[variant_index]

            # Find time
            if cls.widgets["notimeRadio"].get_active():
                secs = 0
                incr = 0
                moves = 0
            elif cls.widgets["blitzRadio"].get_active():
                secs = cls.ngblitz_min.get_value_as_int() * 60
                incr = cls.ngblitz_gain.get_value_as_int()
                moves = 0
            elif cls.widgets["rapidRadio"].get_active():
                secs = cls.ngrapid_min.get_value_as_int() * 60
                incr = cls.ngrapid_gain.get_value_as_int()
                moves = 0
            elif cls.widgets["normalRadio"].get_active():
                secs = cls.ngnormal_min.get_value_as_int() * 60
                incr = cls.ngnormal_gain.get_value_as_int()
                moves = 0
            elif cls.widgets["classicalRadio"].get_active():
                secs = cls.ngclassical_min.get_value_as_int() * 60
                incr = 0
                moves = cls.ngclassical_moves.get_value_as_int()

            # Find players
            player0combo = cls.widgets["whitePlayerCombobox"]
            player0 = player0combo.get_active()

            tree_iter = player0combo.get_active_iter()
            if tree_iter is not None:
                model = player0combo.get_model()
                name0 = model[tree_iter][1]

            diffi0 = int(cls.widgets["skillSlider1"].get_value())

            player1combo = cls.widgets["blackPlayerCombobox"]
            player1 = player1combo.get_active()

            tree_iter = player1combo.get_active_iter()
            if tree_iter is not None:
                model = player1combo.get_model()
                name1 = model[tree_iter][1]

            diffi1 = int(cls.widgets["skillSlider2"].get_value())

            # Prepare players
            playertups = []
            for i, playerno, name, diffi, color in ((0, player0, name0, diffi0, WHITE),
                                                    (1, player1, name1, diffi1, BLACK)):
                if playerno > 0:
                    engine = discoverer.getEngineByName(name)
                    playertups.append((ARTIFICIAL, discoverer.initPlayerEngine,
                                       [engine, color, diffi, variant, secs,
                                        incr, moves], name))
                else:
                    if not playertups or playertups[0][0] != LOCAL:
                        name = conf.get("firstName")
                    else:
                        name = conf.get("secondName")
                    playertups.append((LOCAL, Human, (color, name), name))

            # Set forcePonderOff initPlayerEngine param True in engine-engine games
            if playertups[0][0] == ARTIFICIAL and playertups[1][
                    0] == ARTIFICIAL:
                playertups[0][2].append(True)
                playertups[1][2].append(True)

            timemodel = TimeModel(secs, incr, moves=moves)
            gamemodel = GameModel(timemodel, variant)

            if not validate(gamemodel):
                return
            else:
                cls.widgets["newgamedialog"].hide()
                cls.widgets["newgamedialog"].disconnect(handlerId)
                callback(gamemodel, playertups[0], playertups[1])
Beispiel #52
0
    def __init__(self, widgets):

        # Init open dialog

        opendialog = Gtk.FileChooserDialog(
            _("Open Sound File"), mainwindow(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.ACCEPT))

        for dir in self.SOUND_DIRS:
            if os.path.isdir(dir):
                opendialog.set_current_folder(dir)
                break

        soundfilter = Gtk.FileFilter()
        soundfilter.set_name(_("Sound files"))
        soundfilter.add_mime_type("audio/%s" % EXT)
        soundfilter.add_pattern("*.%s" % EXT)
        opendialog.add_filter(soundfilter)

        # Get combo icons

        icons = ((_("No sound"), "audio-volume-muted", "audio-volume-muted"),
                 (_("Beep"), "stock_bell", "audio-x-generic"),
                 (_("Select sound file..."), "gtk-open", "document-open"))

        items = []
        for level, stock, altstock in icons:
            image = load_icon(16, stock, altstock)
            items += [(image, level)]

        audioIco = load_icon(16, "audio-x-generic")

        # Set-up combos

        def callback(combobox, index):
            if combobox.get_active() == SOUND_SELECT:
                if opendialog.run() == Gtk.ResponseType.ACCEPT:
                    uri = opendialog.get_uri()
                    model = combobox.get_model()
                    conf.set("sounduri%d" % index, uri)
                    label = unquote(os.path.split(uri)[1])
                    if len(model) == 3:
                        model.append([audioIco, label])
                    else:
                        model.set(model.get_iter((3, )), 1, label)
                    combobox.set_active(3)
                else:
                    combobox.set_active(
                        conf.get("soundcombo%d" % index, SOUND_MUTE))
                opendialog.hide()

        for i in range(COUNT_OF_SOUNDS):
            combo = widgets["sound%dcombo" % i]
            uistuff.createCombo(combo, items, name="soundcombo%d" % i)
            combo.connect("changed", callback, i)

            label = widgets["soundlabel%d" % i]
            label.props.mnemonic_widget = combo

            uri = conf.get("sounduri%d" % i, "")
            if os.path.isfile(url2pathname(uri[5:])):
                model = combo.get_model()
                model.append([audioIco, unquote(os.path.split(uri)[1])])

        for i in range(COUNT_OF_SOUNDS):
            if conf.get("soundcombo%d" % i, SOUND_MUTE) == SOUND_URI and \
                    not os.path.isfile(url2pathname(conf.get("sounduri%d" % i, "")[5:])):
                conf.set("soundcombo%d" % i, SOUND_MUTE)
            uistuff.keep(widgets["sound%dcombo" % i], "soundcombo%d" % i)

        # Init play button

        def playCallback(button, index):
            SoundTab.playAction(index)

        for i in range(COUNT_OF_SOUNDS):
            button = widgets["sound%dbutton" % i]
            button.connect("clicked", playCallback, i)

        # Init 'use sound" checkbutton

        def checkCallBack(*args):
            checkbox = widgets["useSounds"]
            widgets["sounds_frame"].set_property("sensitive",
                                                 checkbox.get_active())

        conf.notify_add("useSounds", checkCallBack)
        widgets["useSounds"].set_active(True)
        uistuff.keep(widgets["useSounds"], "useSounds")
        checkCallBack()

        if not self.getPlayer().ready:
            widgets["useSounds"].set_sensitive(False)
            widgets["useSounds"].set_active(False)

        uistuff.keep(widgets["alarm_spin"], "alarm_spin", first_value=15)
Beispiel #53
0
    def saveGameAs(self, game, position=None, export=False):
        savedialog, savecombo = get_save_dialog(export)

        # Keep running the dialog until the user has canceled it or made an error
        # free operation
        title = _("Save Game") if not export else _("Export position")
        savedialog.set_title(title)
        while True:
            filename = "%s-%s" % (game.players[0], game.players[1])
            savedialog.set_current_name(filename.replace(" ", "_"))

            res = savedialog.run()
            if res != Gtk.ResponseType.ACCEPT:
                break

            uri = savedialog.get_filename()
            ending = os.path.splitext(uri)[1]
            if ending.startswith("."):
                ending = ending[1:]
            append = False

            index = savecombo.get_active()
            if index == 0:
                if ending not in enddir:
                    d = Gtk.MessageDialog(mainwindow(),
                                          type=Gtk.MessageType.ERROR,
                                          buttons=Gtk.ButtonsType.OK)
                    folder, file = os.path.split(uri)
                    d.set_markup(
                        _("<big><b>Unknown file type '%s'</b></big>") % ending)
                    d.format_secondary_text(
                        _("Was unable to save '%(uri)s' as PyChess doesn't know the format '%(ending)s'."
                          ) % {
                              'uri': uri,
                              'ending': ending
                          })
                    d.run()
                    d.destroy()
                    continue
                else:
                    saver = enddir[ending]
            else:
                format = exportformats[index] if export else saveformats[index]
                saver = format[2]
                if ending not in enddir or not saver == enddir[ending]:
                    uri += ".%s" % saver.__ending__

            if os.path.isfile(uri) and not os.access(uri, os.W_OK):
                d = Gtk.MessageDialog(mainwindow(),
                                      type=Gtk.MessageType.ERROR,
                                      buttons=Gtk.ButtonsType.OK)
                d.set_markup(
                    _("<big><b>Unable to save file '%s'</b></big>") % uri)
                d.format_secondary_text(
                    _("You don't have the necessary rights to save the file.\n\
    Please ensure that you have given the right path and try again."))
                d.run()
                d.destroy()
                continue

            if os.path.isfile(uri):
                d = Gtk.MessageDialog(mainwindow(),
                                      type=Gtk.MessageType.QUESTION)
                d.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                              _("_Replace"), Gtk.ResponseType.ACCEPT)
                if saver.__append__:
                    d.add_buttons(Gtk.STOCK_ADD, 1)
                d.set_title(_("File exists"))
                folder, file = os.path.split(uri)
                d.set_markup(
                    _("<big><b>A file named '%s' already exists. Would you like to replace it?</b></big>"
                      ) % file)
                d.format_secondary_text(
                    _("The file already exists in '%s'. If you replace it, its content will be overwritten."
                      ) % folder)
                replaceRes = d.run()
                d.destroy()

                if replaceRes == 1:
                    append = True
                elif replaceRes == Gtk.ResponseType.CANCEL:
                    continue
            else:
                print(repr(uri))

            try:
                flip = self.cur_gmwidg().board.view.rotation > 0
                game.save(uri, saver, append, position, flip)
            except IOError as e:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.ERROR)
                d.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK)
                d.set_title(_("Could not save the file"))
                d.set_markup(
                    _("<big><b>PyChess was not able to save the game</b></big>"
                      ))
                d.format_secondary_text(
                    _("The error was: %s") % ", ".join(str(a) for a in e.args))
                d.run()
                d.destroy()
                continue

            break

        savedialog.destroy()
        return res
    def __init__(self):
        self.window = Gtk.Window(
            Gtk.WindowType.TOPLEVEL, title=_("Ask for permissions")
        )
        self.window.set_transient_for(mainwindow())
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        gtk_version = (Gtk.get_major_version(), Gtk.get_minor_version())
        if gtk_version >= (3, 12):
            vbox.props.margin_start = 9
            vbox.props.margin_end = 9
        else:
            vbox.props.margin_left = 9
            vbox.props.margin_right = 9
        vbox.props.margin_bottom = 9
        self.window.add(vbox)
        uistuff.keepWindowSize(
            "externalsdialog", self.window, (320, 240), uistuff.POSITION_CENTER
        )

        label = Gtk.Label(
            _(
                "Some of PyChess features needs your permission to download external programs"
            )
        )
        vbox.pack_start(label, True, True, 0)

        box = Gtk.Box()
        check_button = Gtk.CheckButton(_("database querying needs scoutfish"))
        check_button.set_active(conf.get("download_scoutfish"))
        check_button.connect(
            "toggled", lambda w: conf.set("download_scoutfish", w.get_active())
        )
        box.add(check_button)
        link = "https://github.com/pychess/scoutfish"
        link_button = Gtk.LinkButton(link, link)
        box.add(link_button)
        vbox.pack_start(box, False, False, 0)

        box = Gtk.Box()
        check_button = Gtk.CheckButton(_("database opening tree needs chess_db"))
        check_button.set_active(conf.get("download_chess_db"))
        check_button.connect(
            "toggled", lambda w: conf.set("download_chess_db", w.get_active())
        )
        box.add(check_button)
        link = "https://github.com/pychess/chess_db"
        link_button = Gtk.LinkButton(link, link)
        box.add(link_button)
        vbox.pack_start(box, False, False, 0)

        box = Gtk.Box()
        check_button = Gtk.CheckButton(_("ICC lag compensation needs timestamp"))
        check_button.set_active(conf.get("download_timestamp"))
        check_button.connect(
            "toggled", lambda w: conf.set("download_timestamp", w.get_active())
        )
        box.add(check_button)
        link = "http://download.chessclub.com/timestamp/"
        link_button = Gtk.LinkButton(link, link)
        box.add(link_button)
        vbox.pack_start(box, False, False, 0)

        check_button = Gtk.CheckButton(_("Don't show this dialog on startup."))
        check_button.set_active(conf.get("dont_show_externals_at_startup"))
        check_button.connect(
            "toggled",
            lambda w: conf.set("dont_show_externals_at_startup", w.get_active()),
        )
        vbox.pack_start(check_button, True, True, 0)

        buttonbox = Gtk.ButtonBox()
        close_button = Gtk.Button.new_from_stock(Gtk.STOCK_OK)
        close_button.connect("clicked", self.on_close_clicked)
        self.window.connect("delete_event", lambda w, a: self.window.destroy())
        buttonbox.add(close_button)
        vbox.pack_start(buttonbox, False, False, 0)