コード例 #1
0
ファイル: ChatWindow.py プロジェクト: sally0813/pychess
    def initUi (self):
        self.window = Gtk.Window()
        self.window.set_border_width(12)
        self.window.set_icon_name("pychess")
        self.window.set_title("PyChess - Internet Chess Chat")
        self.window.connect("delete-event", lambda w,e: w.hide() or True)

        uistuff.keepWindowSize("chatwindow", self.window, defaultSize=(650,400))

        dock = PyDockTop("icchat")
        dock.show()
        self.window.add(dock)

        leaf = dock.dock(self.viewspanel, CENTER, Gtk.Label(label="chat"), "chat")
        leaf.setDockable(False)

        self.channelspanel.connect('conversationAdded', self.onConversationAdded)
        self.channelspanel.connect('conversationRemoved', self.onConversationRemoved)
        self.channelspanel.connect('conversationSelected', self.onConversationSelected)
        leaf.dock(self.channelspanel, WEST, Gtk.Label(label=_("Conversations")), "conversations")

        leaf.dock(self.infopanel, EAST, Gtk.Label(label=_("Conversation info")), "info")

        for panel in self.panels:
            panel.show_all()
            panel.start()
コード例 #2
0
    def initUi(self):
        self.window = Gtk.Window()
        self.window.set_border_width(12)
        self.window.set_icon_name("pychess")
        self.window.set_title("PyChess - Internet Chess Chat")
        self.window.connect("delete-event", lambda w, e: w.hide() or True)

        uistuff.keepWindowSize("chatwindow",
                               self.window,
                               defaultSize=(650, 400))

        dock = PyDockTop("icchat")
        dock.show()
        self.window.add(dock)

        leaf = dock.dock(self.viewspanel, CENTER, Gtk.Label(label="chat"),
                         "chat")
        leaf.setDockable(False)

        self.channelspanel.connect('conversationAdded',
                                   self.onConversationAdded)
        self.channelspanel.connect('conversationRemoved',
                                   self.onConversationRemoved)
        self.channelspanel.connect('conversationSelected',
                                   self.onConversationSelected)
        leaf.dock(self.channelspanel, WEST,
                  Gtk.Label(label=_("Conversations")), "conversations")

        leaf.dock(self.infopanel, EAST,
                  Gtk.Label(label=_("Conversation info")), "info")

        for panel in self.panels:
            panel.show_all()
            panel.start()
コード例 #3
0
ファイル: __init__.py プロジェクト: leogregianin/pychess
class Games(GObject.GObject, Perspective):
    __gsignals__ = {
        'gmwidg_created': (GObject.SignalFlags.RUN_FIRST, None, (object, ))
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "games", _("Games"))

        self.notebooks = {}
        self.first_run = True
        self.gamewidgets = set()
        self.gmwidg_cids = {}
        self.board_cids = {}
        self.notify_cids = defaultdict(list)

        self.key2gmwidg = {}
        self.key2cid = {}

        self.dock = None
        self.dockAlign = None
        self.dockLocation = addUserConfigPrefix("pydock.xml")

    @asyncio.coroutine
    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))

    ################################################################################
    # Saving                                                                       #
    ################################################################################

    def saveGame(self, game, position=None):
        if not game.isChanged():
            return
        if game.uri and isWriteable(game.uri):
            self.saveGameSimple(game.uri, game, position=position)
        else:
            return self.saveGameAs(game, position=position)

    def saveGameSimple(self, uri, game, position=None):
        ending = os.path.splitext(uri)[1]
        if not ending:
            return
        saver = enddir[ending[1:]]
        game.save(uri, saver, append=False, position=position)

    def saveGamePGN(self, game):
        if conf.get("saveOwnGames") and not game.hasLocalPlayer():
            return True

        filename = conf.get("autoSaveFormat")
        filename = filename.replace("#n1", game.tags["White"])
        filename = filename.replace("#n2", game.tags["Black"])
        year, month, day = parseDateTag(game.tags["Date"])
        year = '' if year is None else str(year)
        month = '' if month is None else str(month)
        day = '' if day is None else str(day)
        filename = filename.replace("#y", "%s" % year)
        filename = filename.replace("#m", "%s" % month)
        filename = filename.replace("#d", "%s" % day)
        pgn_path = conf.get("autoSavePath") + "/" + filename + ".pgn"
        append = True
        try:
            if not os.path.isfile(pgn_path):
                # create new file
                with open(pgn_path, "w"):
                    pass
            base_offset = os.path.getsize(pgn_path)

            # save to .sqlite
            database_path = os.path.splitext(pgn_path)[0] + '.sqlite'
            database.save(database_path, game, base_offset)

            # save to .scout
            from pychess.Savers.pgn import scoutfish_path
            if scoutfish_path is not None:
                pgn_text = pgn.save(StringIO(), game)

                tmp = tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False)
                pgnfile = tmp.name
                with tmp.file as f:
                    f.write(pgn_text)

                # create new .scout from pgnfile we are importing
                args = [scoutfish_path, "make", pgnfile, "%s" % base_offset]
                output = subprocess.check_output(args, stderr=subprocess.STDOUT)

                # append it to our existing one
                if output.decode().find(u"Processing...done") > 0:
                    old_scout = os.path.splitext(pgn_path)[0] + '.scout'
                    new_scout = os.path.splitext(pgnfile)[0] + '.scout'

                    with open(old_scout, "ab") as file1, open(new_scout, "rb") as file2:
                        file1.write(file2.read())

            # TODO: do we realy want to update .bin ? It can be huge/slow!

            # save to .pgn
            game.save(pgn_path, pgn, append)

            return True
        except IOError:
            return False

    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

    ################################################################################
    # Closing                                                                      #
    ################################################################################
    def closeAllGames(self, gamewidgets):
        log.debug("Games.closeAllGames")
        response = None
        changedPairs = [(gmwidg, gmwidg.gamemodel) for gmwidg in gamewidgets
                        if gmwidg.gamemodel.isChanged()]
        if len(changedPairs) == 0:
            response = Gtk.ResponseType.OK

        elif len(changedPairs) == 1:
            response = self.closeGame(changedPairs[0][0])
        else:
            markup = "<big><b>" + ngettext("There is %d game with unsaved moves.",
                                           "There are %d games with unsaved moves.",
                                           len(changedPairs)) % len(changedPairs) + " " + \
                _("Save moves before closing?") + "</b></big>"

            for gmwidg, game in changedPairs:
                if not gmwidg.gamemodel.isChanged():
                    response = Gtk.ResponseType.OK
                else:
                    if conf.get("autoSave"):
                        x = self.saveGamePGN(game)
                        if x:
                            response = Gtk.ResponseType.OK
                        else:
                            response = None
                            markup = "<b><big>" + _("Unable to save to configured file. \
                                                    Save the games before closing?") + "</big></b>"
                            break

            if response is None:
                widgets = GladeWidgets("saveGamesDialog.glade")
                dialog = widgets["saveGamesDialog"]
                heading = widgets["saveGamesDialogHeading"]
                saveLabel = widgets["saveGamesDialogSaveLabel"]
                treeview = widgets["saveGamesDialogTreeview"]

                heading.set_markup(markup)

                liststore = Gtk.ListStore(bool, str)
                treeview.set_model(liststore)
                renderer = Gtk.CellRendererToggle()
                renderer.props.activatable = True
                treeview.append_column(Gtk.TreeViewColumn("", renderer, active=0))
                treeview.append_column(Gtk.TreeViewColumn("",
                                                          Gtk.CellRendererText(),
                                                          text=1))
                for gmwidg, game in changedPairs:
                    liststore.append((True, "%s %s %s" % (game.players[0], _("vs."), game.players[1])))

                def callback(cell, path):
                    if path:
                        liststore[path][0] = not liststore[path][0]
                    saves = len(tuple(row for row in liststore if row[0]))
                    saveLabel.set_text(ngettext(
                        "_Save %d document", "_Save %d documents", saves) % saves)
                    saveLabel.set_use_underline(True)

                renderer.connect("toggled", callback)

                callback(None, None)

                while True:
                    response = dialog.run()
                    if response == Gtk.ResponseType.YES:
                        for i in range(len(liststore) - 1, -1, -1):
                            checked, name = liststore[i]
                            if checked:
                                cgmwidg, cgame = changedPairs[i]
                                if self.saveGame(cgame) == Gtk.ResponseType.ACCEPT:
                                    liststore.remove(liststore.get_iter((i, )))
                                    del changedPairs[i]
                                    if cgame.status in UNFINISHED_STATES:
                                        cgame.end(ABORTED, ABORTED_AGREEMENT)
                                    cgame.terminate()
                                    self.delGameWidget(cgmwidg)
                                else:
                                    break
                        else:
                            break
                    else:
                        break
                dialog.destroy()

        if response not in (Gtk.ResponseType.DELETE_EVENT,
                            Gtk.ResponseType.CANCEL):
            pairs = [(gmwidg, gmwidg.gamemodel) for gmwidg in gamewidgets]
            for gmwidg, game in pairs:
                if game.status in UNFINISHED_STATES:
                    game.end(ABORTED, ABORTED_AGREEMENT)
                game.terminate()
                if gmwidg.notebookKey in self.key2gmwidg:
                    self.delGameWidget(gmwidg)

        return response

    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

    def delGameWidget(self, gmwidg):
        """ Remove the widget from the GUI after the game has been terminated """
        log.debug("Games.delGameWidget: starting %s" % repr(gmwidg))
        gmwidg.closed = True
        gmwidg.emit("closed")

        called_from_preferences = False
        window_list = Gtk.Window.list_toplevels()
        widgets = gamewidget.getWidgets()
        for window in window_list:
            if window.is_active() and window == widgets["preferences"]:
                called_from_preferences = True
                break

        pageNum = gmwidg.getPageNumber()
        headbook = self.getheadbook()

        if gmwidg.notebookKey in self.key2gmwidg:
            del self.key2gmwidg[gmwidg.notebookKey]

        if gmwidg.notebookKey in self.key2cid:
            headbook.disconnect(self.key2cid[gmwidg.notebookKey])
            del self.key2cid[gmwidg.notebookKey]

        headbook.remove_page(pageNum)
        for notebook in self.notebooks.values():
            notebook.remove_page(pageNum)

        if headbook.get_n_pages() == 1 and conf.get("hideTabs"):
            self.show_tabs(False)

        if headbook.get_n_pages() == 0:
            if not called_from_preferences:
                # If the last (but not the designGW) gmwidg was closed
                # and we are FICS-ing, present the FICS lounge
                perspective_manager.disable_perspective("games")

        gmwidg._del()

    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("games", perspective_widget)

        self.notebooks = {"board": new_notebook("board"),
                          "buttons": new_notebook("buttons"),
                          "messageArea": new_notebook("messageArea")}
        self.main_notebook = self.notebooks["board"]
        for panel in self.sidePanels:
            self.notebooks[panel_name(panel.__name__)] = new_notebook(panel_name(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"))

        # 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"], None)
        for panel in self.sidePanels:
            self.docks[panel_name(panel.__name__)][1] = self.notebooks[panel_name(panel.__name__)]

        self.load_from_xml()

        # Default layout of side panels
        if not os.path.isfile(self.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(self.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()

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

        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)

    def getheadbook(self):
        if len(self.key2gmwidg) == 0:
            return None
        headbook = self.widget.get_children()[0].get_children()[0].get_child()
        # to help StoryText create widget description
        # headbook.get_tab_label_text = customGetTabLabelText
        return headbook

    def cur_gmwidg(self):
        if len(self.key2gmwidg) == 0:
            return None
        headbook = self.getheadbook()
        notebookKey = headbook.get_nth_page(headbook.get_current_page())
        return self.key2gmwidg[notebookKey]

    def customGetTabLabelText(self, child):
        gmwidg = self.key2gmwidg[child]
        return gmwidg.display_text

    def zoomToBoard(self, view_zoomed):
        if not self.notebooks["board"].get_parent():
            return
        if view_zoomed:
            self.notebooks["board"].get_parent().get_parent().zoomUp()
        else:
            self.notebooks["board"].get_parent().get_parent().zoomDown()

    def show_tabs(self, show):
        head = self.getheadbook()
        if head is None:
            return
        head.set_show_tabs(show)

    def tabsCallback(self, widget):
        head = self.getheadbook()
        if not head:
            return
        if head.get_n_pages() == 1:
            self.show_tabs(not conf.get("hideTabs"))

    def attachGameWidget(self, gmwidg):
        log.debug("attachGameWidget: %s" % gmwidg)
        if self.first_run:
            self.init_layout()
            self.first_run = False
        perspective_manager.activate_perspective("games")

        gmwidg.panels = [panel.Sidepanel().load(gmwidg) for panel in self.sidePanels]
        self.key2gmwidg[gmwidg.notebookKey] = gmwidg
        headbook = self.getheadbook()

        headbook.append_page(gmwidg.notebookKey, gmwidg.tabcontent)
        gmwidg.notebookKey.show_all()

        if hasattr(headbook, "set_tab_reorderable"):
            headbook.set_tab_reorderable(gmwidg.notebookKey, True)

        def callback(notebook, gpointer, page_num, gmwidg):
            if notebook.get_nth_page(page_num) == gmwidg.notebookKey:
                gmwidg.infront()
                if gmwidg.gamemodel.players and gmwidg.gamemodel.isObservationGame():
                    gmwidg.light_on_off(False)
                    text = gmwidg.game_info_label.get_text()
                    gmwidg.game_info_label.set_markup(
                        '<span color="black" weight="bold">%s</span>' % text)

        self.key2cid[gmwidg.notebookKey] = headbook.connect_after("switch-page", callback, gmwidg)
        gmwidg.infront()

        align = gamewidget.createAlignment(0, 0, 0, 0)
        align.show()
        align.add(gmwidg.infobar)
        self.notebooks["messageArea"].append_page(align, None)
        self.notebooks["board"].append_page(gmwidg.boardvbox, None)
        gmwidg.boardvbox.show_all()
        for panel, instance in zip(self.sidePanels, gmwidg.panels):
            self.notebooks[panel_name(panel.__name__)].append_page(instance, None)
            instance.show_all()
        self.notebooks["buttons"].append_page(gmwidg.stat_hbox, None)
        gmwidg.stat_hbox.show_all()

        if headbook.get_n_pages() == 1:
            self.show_tabs(not conf.get("hideTabs"))
        else:
            # We should always show tabs if more than one exists
            self.show_tabs(True)

        headbook.set_current_page(-1)

        widgets = gamewidget.getWidgets()
        if headbook.get_n_pages() == 1 and not widgets["show_sidepanels"].get_active():
            self.zoomToBoard(True)
コード例 #4
0
ファイル: __init__.py プロジェクト: vishnugonela/pychess
class Database(GObject.GObject, Perspective):
    __gsignals__ = {
        'chessfile_opened0': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_opened': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_closed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'chessfile_imported':
        (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'bookfile_created': (GObject.SignalFlags.RUN_FIRST, None, ()),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "database", _("Database"))
        self.widgets = gamewidget.getWidgets()
        self.first_run = True
        self.chessfile = None
        self.chessfiles = []
        self.importer = None
        self.gamelists = []
        self.filter_panels = []
        self.opening_tree_panels = []
        self.preview_panels = []
        self.notebooks = {}
        self.page_dict = {}
        self.connect("chessfile_opened0", self.on_chessfile_opened0)
        self.dockLocation = addUserConfigPrefix("pydock-database.xml")

    @property
    def gamelist(self):
        if self.chessfile is None:
            return None
        else:
            return self.gamelists[self.chessfiles.index(self.chessfile)]

    @property
    def filter_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.filter_panels[self.chessfiles.index(self.chessfile)]

    @property
    def opening_tree_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.opening_tree_panels[self.chessfiles.index(
                self.chessfile)]

    @property
    def preview_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.preview_panels[self.chessfiles.index(self.chessfile)]

    def create_toolbuttons(self):
        self.import_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CONVERT)
        self.import_button.set_tooltip_text(_("Import PGN file"))
        self.import_button.connect("clicked", self.on_import_clicked)

        self.save_as_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.set_tooltip_text(_("Save to PGN file as..."))
        self.save_as_button.connect("clicked", self.on_save_as_clicked)

    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.progressbar = 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.progressbar, 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])

    def on_switch_page(self, notebook, page, page_num):
        if page in self.page_dict:
            self.chessfile = self.page_dict[page][0]
            i = self.chessfiles.index(self.chessfile)

            self.notebooks["gamelist"].set_current_page(i)
            self.notebooks["OpeningTreePanel"].set_current_page(i)
            self.notebooks["FilterPanel"].set_current_page(i)
            self.notebooks["PreviewPanel"].set_current_page(i)

    def set_sensitives(self, on):
        self.import_button.set_sensitive(on)
        self.widgets["import_chessfile"].set_sensitive(on)
        self.widgets["database_save_as"].set_sensitive(on)
        self.widgets["create_book"].set_sensitive(on)
        self.widgets["import_endgame_nl"].set_sensitive(on)
        self.widgets["import_twic"].set_sensitive(on)

        if on:
            gamewidget.getWidgets()["copy_pgn"].set_property('sensitive', on)
            gamewidget.getWidgets()["copy_fen"].set_property('sensitive', on)
        else:
            persp = perspective_manager.get_perspective("games")
            if persp.cur_gmwidg() is None:
                gamewidget.getWidgets()["copy_pgn"].set_property(
                    'sensitive', on)
                gamewidget.getWidgets()["copy_fen"].set_property(
                    'sensitive', on)

    def open_chessfile(self, filename):
        if self.first_run:
            self.init_layout()
            self.first_run = False

        perspective_manager.activate_perspective("database")

        self.progress_dialog.set_title(_("Open"))
        self.spinner.show()
        self.spinner.start()

        def opening():
            if filename.endswith(".pgn"):
                GLib.idle_add(self.progressbar.show)
                GLib.idle_add(self.progressbar.set_text,
                              _("Opening chessfile..."))
                chessfile = PGNFile(protoopen(filename), self.progressbar)
                self.importer = chessfile.init_tag_database()
                if self.importer is not None and self.importer.cancel:
                    chessfile.tag_database.close()
                    if os.path.isfile(chessfile.sqlite_path):
                        os.remove(chessfile.sqlite_path)
                    chessfile = None
                else:
                    chessfile.init_scoutfish()
                    chessfile.init_chess_db()
            elif filename.endswith(".epd"):
                self.importer = None
                chessfile = epd.load(protoopen(filename))
            elif filename.endswith(".olv"):
                self.importer = None
                chessfile = olv.load(protoopen(filename, encoding="utf-8"))
            elif filename.endswith(".fen"):
                self.importer = None
                chessfile = fen.load(protoopen(filename))
            else:
                self.importer = None
                chessfile = None

            GLib.idle_add(self.spinner.stop)
            GLib.idle_add(self.spinner.hide)
            GLib.idle_add(self.progress_dialog.hide)

            if chessfile is not None:
                self.chessfile = chessfile
                self.chessfiles.append(chessfile)
                GLib.idle_add(self.emit, "chessfile_opened0", chessfile)
            else:
                if self.chessfile is None:
                    self.close(None)

        thread = threading.Thread(target=opening)
        thread.daemon = True
        thread.start()

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            if self.importer is not None:
                self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_chessfile_opened0(self, persp, chessfile):
        page = Gtk.Alignment()
        tabcontent, close_button = self.get_tabcontent(chessfile)
        self.headbook.append_page(page, tabcontent)
        self.page_dict[page] = (chessfile, close_button)
        page.show_all()

        gamelist = GameList(self)
        self.gamelists.append(gamelist)
        opening_tree_panel = OpeningTreePanel(self)
        self.opening_tree_panels.append(opening_tree_panel)
        filter_panel = FilterPanel(self)
        self.filter_panels.append(filter_panel)
        preview_panel = PreviewPanel(self)
        self.preview_panels.append(preview_panel)

        self.notebooks["gamelist"].append_page(gamelist.box)
        self.notebooks["OpeningTreePanel"].append_page(opening_tree_panel.box)
        self.notebooks["FilterPanel"].append_page(filter_panel.box)
        self.notebooks["PreviewPanel"].append_page(preview_panel.box)

        self.headbook.set_current_page(self.headbook.get_n_pages() - 1)

        gamelist.load_games()
        opening_tree_panel.update_tree(load_games=False)

        self.set_sensitives(True)
        self.emit("chessfile_opened", chessfile)

    def close(self, close_button):
        for page in list(self.page_dict.keys()):
            if self.page_dict[page][1] == close_button:
                chessfile = self.page_dict[page][0]
                i = self.chessfiles.index(chessfile)
                self.notebooks["gamelist"].remove_page(i)
                self.notebooks["OpeningTreePanel"].remove_page(i)
                self.notebooks["FilterPanel"].remove_page(i)
                self.notebooks["PreviewPanel"].remove_page(i)
                del self.gamelists[i]
                del self.filter_panels[i]
                del self.chessfiles[i]
                chessfile.close()

                del self.page_dict[page]
                self.headbook.remove_page(self.headbook.page_num(page))
                break

        if len(self.chessfiles) == 0:
            self.chessfile = None
            self.set_sensitives(False)
            perspective_manager.disable_perspective("database")

        self.emit("chessfile_closed")

    def on_import_endgame_nl(self):
        self.do_import(JvR)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_twic(self):
        LATEST = get_latest_twic()
        if LATEST is None:
            return

        html = "http://www.theweekinchess.com/html/twic%s.html"
        twic = []

        pgn = "https://raw.githubusercontent.com/rozim/ChessData/master/Twic/fix-twic%s.pgn"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(210, 920):
            twic.append((html % i, pgn % i))

        pgn = "http://www.theweekinchess.com/zips/twic%sg.zip"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(920, LATEST + 1):
            twic.append((html % i, pgn % i))

        twic.append((html % LATEST, pgn % LATEST))

        # import limited to latest twic .pgn for now
        twic = twic[-1:]

        self.do_import(twic)
        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    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()

    def save_records(self, records, to_file):
        f = self.chessfile.handle
        for i, rec in enumerate(records):
            offs = rec["Offset"]

            f.seek(offs)
            game = ''
            for line in f:
                if line.startswith('[Event "'):
                    if game:
                        break  # Second one, start of next game
                    else:
                        game = line  # First occurence
                elif game:
                    game += line
            to_file.write(game)

    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()

    # @profile_me
    def importing(self, filenames):
        drop_indexes(self.chessfile.engine)

        self.importer = PgnImport(self.chessfile, append_pgn=True)
        self.importer.initialize()
        for i, filename in enumerate(filenames):
            if len(filenames) > 1:
                GLib.idle_add(self.progressbar0.set_fraction,
                              i / float(len(filenames)))
            if self.importer.cancel:
                break
            if isinstance(filename, tuple):
                info_link, pgn_link = filename
                self.importer.do_import(pgn_link,
                                        info=info_link,
                                        progressbar=self.progressbar)
            else:
                self.importer.do_import(filename, progressbar=self.progressbar)

        GLib.idle_add(self.progressbar.set_text, _("Recreating indexes..."))

        # .sqlite
        create_indexes(self.chessfile.engine)

        # .scout
        self.chessfile.init_scoutfish()

        # .bin
        self.chessfile.init_chess_db()

        self.chessfile.set_tag_filter(None)
        self.chessfile.set_fen_filter(None)
        self.chessfile.set_scout_filter(None)
        GLib.idle_add(self.gamelist.load_games)
        GLib.idle_add(self.emit, "chessfile_imported", self.chessfile)
        GLib.idle_add(self.progressbar0.hide)
        GLib.idle_add(self.progress_dialog.hide)

    def do_import(self, filenames):
        self.progress_dialog.set_title(_("Import"))
        if len(filenames) > 1:
            self.progressbar0.show()
        self.progressbar.show()
        self.progressbar.set_text(_("Preparing to start import..."))

        thread = threading.Thread(target=self.importing, args=(filenames, ))
        thread.daemon = True
        thread.start()

    def process_records(self, callback, cancel_event, *args):
        counter = 0

        records, plys = self.chessfile.get_records(FIRST_PAGE)
        callback(records, *args)
        GLib.idle_add(self.progressbar.set_text,
                      _("%s games processed") % counter)

        while not cancel_event.is_set():
            records, plys = self.chessfile.get_records(NEXT_PAGE)
            if records:
                callback(records, *args)
                counter += len(records)
                GLib.idle_add(self.progressbar.set_text,
                              _("%s games processed") % counter)
            else:
                break

    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()

    def feed_book(self, records, positions):
        for rec in records:
            model = GameModel()

            if rec["Result"] == DRAW:
                score = (1, 1)
            elif rec["Result"] == WHITEWON:
                score = (2, 0)
            elif rec["Result"] == BLACKWON:
                score = (0, 2)
            else:
                score = (0, 0)

            fenstr = rec["FEN"]
            variant = self.chessfile.get_variant(rec)

            if variant:
                model.variant = name2variant[variant]
                board = LBoard(model.variant.variant)
            else:
                model.variant = NormalBoard
                board = LBoard()

            if fenstr:
                try:
                    board.applyFen(fenstr)
                except SyntaxError as err:
                    continue
            else:
                board.applyFen(FEN_START)

            boards = [board]

            movetext = self.chessfile.get_movetext(rec)
            boards = self.chessfile.parse_movetext(movetext, boards[0], -1)

            for board in boards:
                if board.plyCount > BOOK_DEPTH:
                    break
                move = board.lastMove
                if move is not None:
                    poly_move = toPolyglot(board.prev, move)
                    # move_str = "%s%s" % (reprCord[FCORD(move)], reprCord[TCORD(move)])
                    # print("%0.16x" % board.prev.hash, poly_move, board.prev.asFen(), move_str)
                    if board.prev.hash in positions:
                        if poly_move in positions[board.prev.hash]:
                            positions[board.prev.hash][poly_move] += score[
                                board.prev.color]
                        else:
                            positions[board.prev.hash][poly_move] = score[
                                board.prev.color]
                    else:
                        # board.prev.asFen(), move_str,
                        positions[board.prev.hash] = {
                            poly_move: score[board.prev.color]
                        }

    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.destroy()

        dialog.destroy()

    def get_tabcontent(self, chessfile):
        tabcontent = createAlignment(0, 0, 0, 0)
        hbox = Gtk.HBox()
        hbox.set_spacing(4)
        hbox.pack_start(createImage(pgn_icon), False, True, 0)

        close_button = Gtk.Button()
        close_button.set_property("can-focus", False)
        close_button.add(createImage(gtk_close))
        close_button.set_relief(Gtk.ReliefStyle.NONE)
        close_button.set_size_request(20, 18)
        close_button.connect("clicked", self.close)
        hbox.pack_end(close_button, False, True, 0)

        name, ext = os.path.splitext(chessfile.path)
        basename = os.path.basename(name)
        info = "%s.%s" % (basename, ext[1:])
        tooltip = _("%(path)s\ncontaining %(count)s games") % (
            {
                "path": chessfile.path,
                "count": chessfile.count
            })
        tabcontent.set_tooltip_text(tooltip)

        label = Gtk.Label(info)
        hbox.pack_start(label, False, True, 0)

        tabcontent.add(hbox)
        tabcontent.show_all()
        return tabcontent, close_button
コード例 #5
0
ファイル: __init__.py プロジェクト: scchess/pychess
class Database(GObject.GObject, Perspective):
    __gsignals__ = {
        'chessfile_opened0': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_opened': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_closed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'chessfile_imported':
        (GObject.SignalFlags.RUN_FIRST, None, (object, )),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "database", _("Database"))
        self.widgets = gamewidget.getWidgets()
        self.first_run = True
        self.chessfile = None
        self.chessfiles = []
        self.importer = None
        self.gamelists = []
        self.filter_panels = []
        self.opening_tree_panels = []
        self.preview_panels = []
        self.notebooks = {}
        self.page_dict = {}
        self.connect("chessfile_opened0", self.on_chessfile_opened0)
        self.dockLocation = addUserConfigPrefix("pydock-database.xml")

    @property
    def gamelist(self):
        if self.chessfile is None:
            return None
        else:
            return self.gamelists[self.chessfiles.index(self.chessfile)]

    @property
    def filter_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.filter_panels[self.chessfiles.index(self.chessfile)]

    @property
    def opening_tree_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.opening_tree_panels[self.chessfiles.index(
                self.chessfile)]

    @property
    def preview_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.preview_panels[self.chessfiles.index(self.chessfile)]

    def create_toolbuttons(self):
        self.import_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CONVERT)
        self.import_button.set_tooltip_text(_("Import PGN file"))
        self.import_button.connect("clicked", self.on_import_clicked)

        self.save_as_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.set_tooltip_text(_("Save to PGN file as..."))
        self.save_as_button.connect("clicked", self.on_save_as_clicked)

    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])

    def on_switch_page(self, notebook, page, page_num):
        if page in self.page_dict:
            self.chessfile = self.page_dict[page][0]
            i = self.chessfiles.index(self.chessfile)

            self.notebooks["gamelist"].set_current_page(i)
            self.notebooks["OpeningTreePanel"].set_current_page(i)
            self.notebooks["FilterPanel"].set_current_page(i)
            self.notebooks["PreviewPanel"].set_current_page(i)

    def set_sensitives(self, on):
        self.import_button.set_sensitive(on)
        self.widgets["import_chessfile"].set_sensitive(on)
        self.widgets["database_save_as"].set_sensitive(on)
        self.widgets["import_endgame_nl"].set_sensitive(on)
        self.widgets["import_twic"].set_sensitive(on)

    def open_chessfile(self, filename):
        if self.first_run:
            self.init_layout()
            self.first_run = False

        perspective_manager.activate_perspective("database")

        self.progress_dialog.set_title(_("Open"))
        self.progressbar0.hide()
        self.spinner.show()
        self.spinner.start()

        def opening():
            if filename.endswith(".pgn"):
                GLib.idle_add(self.progressbar1.show)
                GLib.idle_add(self.progressbar1.set_text,
                              _("Opening chessfile..."))
                chessfile = PGNFile(protoopen(filename), self.progressbar1)
                self.importer = PgnImport(chessfile)
                chessfile.init_tag_database(self.importer)
                if self.importer.cancel:
                    chessfile.tag_database.close()
                    if os.path.isfile(chessfile.sqlite_path):
                        os.remove(chessfile.sqlite_path)
                    chessfile = None
                else:
                    chessfile.init_scoutfish()
                    chessfile.init_chess_db()
            elif filename.endswith(".epd"):
                self.importer = None
                chessfile = epd.load(protoopen(filename))
            elif filename.endswith(".fen"):
                self.importer = None
                chessfile = fen.load(protoopen(filename))
            else:
                self.importer = None
                chessfile = None

            GLib.idle_add(self.spinner.stop)
            GLib.idle_add(self.progress_dialog.hide)

            if chessfile is not None:
                self.chessfile = chessfile
                self.chessfiles.append(chessfile)
                GLib.idle_add(self.emit, "chessfile_opened0", chessfile)
            else:
                if self.chessfile is None:
                    self.close(None)

        thread = threading.Thread(target=opening)
        thread.daemon = True
        thread.start()

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            if self.importer is not None:
                self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_chessfile_opened0(self, persp, chessfile):
        page = Gtk.Alignment()
        tabcontent, close_button = self.get_tabcontent(chessfile)
        self.headbook.append_page(page, tabcontent)
        self.page_dict[page] = (chessfile, close_button)
        page.show_all()

        gamelist = GameList(self)
        self.gamelists.append(gamelist)
        opening_tree_panel = OpeningTreePanel(self)
        self.opening_tree_panels.append(opening_tree_panel)
        filter_panel = FilterPanel(self)
        self.filter_panels.append(filter_panel)
        preview_panel = PreviewPanel(self)
        self.preview_panels.append(preview_panel)

        self.notebooks["gamelist"].append_page(gamelist.box)
        self.notebooks["OpeningTreePanel"].append_page(opening_tree_panel.box)
        self.notebooks["FilterPanel"].append_page(filter_panel.box)
        self.notebooks["PreviewPanel"].append_page(preview_panel.box)

        self.headbook.set_current_page(self.headbook.get_n_pages() - 1)

        gamelist.load_games()
        opening_tree_panel.update_tree(load_games=False)

        self.set_sensitives(True)
        self.emit("chessfile_opened", chessfile)

    def close(self, close_button):
        for page in list(self.page_dict.keys()):
            if self.page_dict[page][1] == close_button:
                chessfile = self.page_dict[page][0]
                i = self.chessfiles.index(chessfile)
                self.notebooks["gamelist"].remove_page(i)
                self.notebooks["OpeningTreePanel"].remove_page(i)
                self.notebooks["FilterPanel"].remove_page(i)
                self.notebooks["PreviewPanel"].remove_page(i)
                del self.gamelists[i]
                del self.filter_panels[i]
                del self.chessfiles[i]
                chessfile.close()

                del self.page_dict[page]
                self.headbook.remove_page(self.headbook.page_num(page))
                break

        if len(self.chessfiles) == 0:
            self.set_sensitives(False)
            perspective_manager.disable_perspective("database")

        self.emit("chessfile_closed")

    def on_import_endgame_nl(self):
        self.do_import(JvR)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_twic(self):
        LATEST = get_latest_twic()
        if LATEST is None:
            return

        html = "http://www.theweekinchess.com/html/twic%s.html"
        twic = []

        pgn = "https://raw.githubusercontent.com/rozim/ChessData/master/Twic/fix-twic%s.pgn"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(210, 920):
            twic.append((html % i, pgn % i))

        pgn = "http://www.theweekinchess.com/zips/twic%sg.zip"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(920, LATEST + 1):
            twic.append((html % i, pgn % i))

        twic.append((html % LATEST, pgn % LATEST))

        # import limited to latest twic .pgn for now
        twic = twic[-1:]

        self.do_import(twic)
        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    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

    def save_records(self, records, to_file):
        f = self.chessfile.handle
        for i, rec in enumerate(records):
            offs = rec["Offset"]

            f.seek(offs)
            game = ''
            for line in f:
                if line.startswith('[Event "'):
                    if game:
                        break  # Second one, start of next game
                    else:
                        game = line  # First occurence
                elif game:
                    game += line
            to_file.write(game)

    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()

    # @profile_me
    def importing(self, filenames):
        drop_indexes(self.chessfile.engine)

        self.importer = PgnImport(self.chessfile, append_pgn=True)
        self.importer.initialize()
        for i, filename in enumerate(filenames):
            GLib.idle_add(self.progressbar0.set_fraction,
                          i / float(len(filenames)))
            # GLib.idle_add(self.progressbar0.set_text, filename)
            if self.importer.cancel:
                break
            if isinstance(filename, tuple):
                info_link, pgn_link = filename
                self.importer.do_import(pgn_link,
                                        info=info_link,
                                        progressbar=self.progressbar1)
            else:
                self.importer.do_import(filename,
                                        progressbar=self.progressbar1)

        GLib.idle_add(self.progressbar1.set_text, _("Recreating indexes..."))

        # .sqlite
        create_indexes(self.chessfile.engine)

        # .scout
        self.chessfile.init_scoutfish()

        # .bin
        self.chessfile.init_chess_db()

        self.chessfile.set_tag_filter(None)
        self.chessfile.set_fen_filter(None)
        self.chessfile.set_scout_filter(None)
        GLib.idle_add(self.gamelist.load_games)
        GLib.idle_add(self.emit, "chessfile_imported", self.chessfile)
        GLib.idle_add(self.progress_dialog.hide)

    def do_import(self, filenames):
        self.progress_dialog.set_title(_("Import"))
        self.spinner.hide()
        if len(filenames) == 1:
            self.progressbar0.hide()
        else:
            self.progressbar0.show()
        self.progressbar1.show()
        self.progressbar1.set_text(_("Preparing to start import..."))

        thread = threading.Thread(target=self.importing, args=(filenames, ))
        thread.daemon = True
        thread.start()

    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()

    def get_tabcontent(self, chessfile):
        tabcontent = createAlignment(0, 0, 0, 0)
        hbox = Gtk.HBox()
        hbox.set_spacing(4)
        hbox.pack_start(createImage(pgn_icon), False, True, 0)

        close_button = Gtk.Button()
        close_button.set_property("can-focus", False)
        close_button.add(createImage(gtk_close))
        close_button.set_relief(Gtk.ReliefStyle.NONE)
        close_button.set_size_request(20, 18)
        close_button.connect("clicked", self.close)
        hbox.pack_end(close_button, False, True, 0)

        name, ext = os.path.splitext(chessfile.path)
        basename = os.path.basename(name)
        info = "%s.%s" % (basename, ext[1:])
        tooltip = "%s\ncontaining %s games" % (chessfile.path, chessfile.count)
        tabcontent.set_tooltip_text(tooltip)

        label = Gtk.Label(info)
        hbox.pack_start(label, False, True, 0)

        tabcontent.add(hbox)
        tabcontent.show_all()
        return tabcontent, close_button
コード例 #6
0
class Learn(GObject.GObject, Perspective):
    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "learn", _("Learn"))
        self.always_on = True

        self.dockLocation = addUserConfigPrefix("pydock-learn.xml")
        self.first_run = True

    def create_toolbuttons(self):
        def on_exit_clicked(button):
            perspective_manager.disable_perspective("learn")

        self.exit_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_QUIT)
        self.exit_button.set_tooltip_text(_("Quit Learning"))
        self.exit_button.set_label("exit")
        self.exit_button.connect("clicked", on_exit_clicked)

    def init_layout(self):
        perspective_manager.set_perspective_toolbuttons("learn", (self.exit_button, ))

        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("learn", perspective_widget)
        perspective_manager.set_perspective_menuitems("learn", self.menuitems)

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

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

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

        self.docks["learnhome"] = (Gtk.Label(label="learnhome"), self.notebooks["learnhome"], 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):
            leaf0 = self.dock.dock(self.docks["learnhome"][1], CENTER, self.docks["learnhome"][0], "learnhome")
            leaf0.setDockable(False)

            leaf = leaf0.dock(self.docks["PuzzlesPanel"][1], WEST, self.docks["PuzzlesPanel"][0], "PuzzlesPanel")
            leaf.dock(self.docks["LessonsPanel"][1], SOUTH, self.docks["LessonsPanel"][0], "LessonsPanel")

            leaf = leaf0.dock(self.docks["LecturesPanel"][1], SOUTH, self.docks["LecturesPanel"][0], "LecturesPanel")
            leaf.dock(self.docks["EndgamesPanel"][1], SOUTH, self.docks["EndgamesPanel"][0], "EndgamesPanel")

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

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

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

        log.debug("Learn.__init__: finished")

    def activate(self):
        if self.first_run:
            self.init_layout()
            self.first_run = False

        learn_home = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        box = Gtk.Box()

        self.tv = Gtk.TreeView()

        color = Gdk.RGBA()
        color.parse("lightblue")

        for i, col in enumerate((_("lichess"), _("wtharvey"), _("yacpdb"), _("lessons"))):
            renderer = Gtk.CellRendererProgress()
            renderer.set_orientation(Gtk.Orientation.VERTICAL)
            renderer.props.height = 100
            renderer.props.inverted = True
            renderer.props.cell_background_rgba = color
            column = Gtk.TreeViewColumn(col, renderer, text=i * 2, value=i * 2 + 1)
            self.tv.append_column(column)

        self.store = Gtk.ListStore(str, int, str, int, str, int, str, int)

        self.update_progress(None, None, None)

        self.tv.set_model(self.store)
        self.tv.get_selection().set_mode(Gtk.SelectionMode.NONE)

        puzzles_solving_progress.connect("progress_updated", self.update_progress)
        lessons_solving_progress.connect("progress_updated", self.update_progress)

        box.pack_start(self.tv, False, False, 6)

        label = Gtk.Label(xpad=6, xalign=0)
        label.set_markup("<b>%s</b>" % _("Progress"))
        learn_home.pack_start(label, False, False, 6)

        learn_home.pack_start(box, False, False, 0)

        learn_home.show_all()

        if not self.first_run:
            self.notebooks["learnhome"].remove_page(-1)
        self.notebooks["learnhome"].append_page(learn_home)

        self.panels = [panel.Sidepanel().load(self) for panel in self.sidePanels]

        for panel, instance in zip(self.sidePanels, self.panels):
            if not self.first_run:
                self.notebooks[panel.__name__].remove_page(-1)
            self.notebooks[panel.__name__].append_page(instance)
            instance.show()

        perspective_manager.activate_perspective("learn")

    def update_progress(self, solving_progress, key, progress):
        self.store.clear()

        # Compute cumulative puzzles solving statistics
        solving_progress = puzzles_solving_progress.read_all()

        stat = [0, 0, 0, 0, 0, 0, 0, 0]
        for filename, progress in solving_progress.items():
            if filename.startswith("lichess"):
                stat[0] += len(progress)
                stat[1] += progress.count(1)
            elif filename.startswith("mate_in"):
                stat[2] += len(progress)
                stat[3] += progress.count(1)
            elif filename.endswith(".olv"):
                stat[4] += len(progress)
                stat[5] += progress.count(1)

        # Compute cumulative lessons solving statistics
        solving_progress = lessons_solving_progress.read_all()

        for filename, progress in solving_progress.items():
            stat[6] += len(progress)
            stat[7] += progress.count(1)

        stats = []
        for i in range(4):
            percent = 0 if not stat[i * 2 + 1] else round((stat[i * 2 + 1] * 100.) / stat[i * 2])
            stats.append("%s%%" % percent)
            stats.append(percent)

        self.store.append(stats)
コード例 #7
0
class Database(GObject.GObject, Perspective):
    __gsignals__ = {
        'chessfile_opened': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_closed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'chessfile_imported': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_switched': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "database", _("Database"))
        self.gamelist = None

    def create_toolbuttons(self):
        self.import_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CONVERT)
        self.import_button.set_tooltip_text(_("Import PGN file"))
        self.import_button.connect("clicked", self.on_import_clicked)

        self.close_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CLOSE)
        self.close_button.set_tooltip_text(_("Close"))
        self.close_button.connect("clicked", self.close)

    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("database", perspective_widget)

        self.gamelist = GameList(database.load(None))
        self.switcher_panel = SwitcherPanel(self.gamelist)
        self.opening_tree_panel = OpeningTreePanel(self.gamelist)
        self.filter_panel = FilterPanel(self.gamelist)
        self.preview_panel = PreviewPanel(self.gamelist)

        self.progressbar0 = Gtk.ProgressBar(show_text=True)
        self.progressbar = Gtk.ProgressBar(show_text=True)
        self.progress_dialog = Gtk.Dialog("Import", None, 0, (
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
        self.progress_dialog.get_content_area().pack_start(self.progressbar0, True, True, 0)
        self.progress_dialog.get_content_area().pack_start(self.progressbar, True, True, 0)
        self.progress_dialog.get_content_area().show_all()

        perspective = perspective_manager.get_perspective("database")

        self.dock = PyDockTop("database", perspective)
        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.gamelist.box),
            "switcher": (dock_panel_tab(_("Database switcher"), "", addDataPrefix("glade/panel_docker.svg")), self.switcher_panel.alignment),
            "openingtree": (dock_panel_tab(_("Opening tree"), "", addDataPrefix("glade/panel_docker.svg")), self.opening_tree_panel.box),
            "filter": (dock_panel_tab(_("Filter"), "", addDataPrefix("glade/panel_docker.svg")), self.filter_panel.box),
            "preview": (dock_panel_tab(_("Preview"), "", addDataPrefix("glade/panel_docker.svg")), self.preview_panel.box),
        }

        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(None,
                                            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["filter"][1], EAST, docks["filter"][0], "filter")
            leaf = leaf.dock(docks["openingtree"][1], SOUTH, docks["openingtree"][0], "openingtree")
            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.close_button])

        self.switcher_panel.connect("chessfile_switched", self.on_chessfile_switched)

    def open_chessfile(self, filename):
        if filename.endswith(".pdb"):
            chessfile = database.load(filename)
        elif filename.endswith(".pgn"):
            chessfile = pgn.load(protoopen(filename))
        elif filename.endswith(".epd"):
            chessfile = epd.load(protoopen(filename))
        elif filename.endswith(".fen"):
            chessfile = fen.load(protoopen(filename))
        else:
            return

        if self.gamelist is None:
            self.init_layout()

        perspective_manager.activate_perspective("database")
        self.emit("chessfile_opened", chessfile)

    def close(self, widget):
        self.emit("chessfile_closed")

    def on_chessfile_switched(self, switcher, chessfile):
        self.emit("chessfile_switched", chessfile)

    def on_import_endgame_nl(self):
        self.do_import(JvR)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_twic(self):
        LATEST = get_latest_twic()
        if LATEST is None:
            return

        html = "http://www.theweekinchess.com/html/twic%s.html"
        twic = []

        pgn = "https://raw.githubusercontent.com/rozim/ChessData/master/Twic/fix-twic%s.pgn"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(210, 920):
            twic.append((html % i, pgn % i))

        pgn = "http://www.theweekinchess.com/zips/twic%sg.zip"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(920, LATEST + 1):
            twic.append((html % i, pgn % i))

        twic.append((html % LATEST, pgn % LATEST))

        # TODO: importing all twic .pgn files creates a huge (~8Gb) .pdb
        # and sqlite seems too slow to handle my current selects
        # until I find better solution import will be limited to latest twic .pgn
        twic = twic[-1:]

        self.do_import(twic)
        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_update_players(self):
        def importing():
            self.importer = FIDEPlayersImport(self.gamelist.chessfile.engine)
            self.importer.import_players(progressbar=self.progressbar)
            GLib.idle_add(self.progress_dialog.hide)

        thread = threading.Thread(target=importing)
        thread.daemon = True
        thread.start()

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            _("Open chess file"), None, 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)

        dialog = NestedFileChooserDialog(dialog)
        filenames = dialog.run()
        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()

    def do_import(self, filenames):
        if len(filenames) == 1:
            self.progressbar0.hide()
        else:
            self.progressbar0.show()
        self.progressbar.set_text("Preparing to start import...")

        # @profile_me
        def importing():
            drop_indexes(self.gamelist.chessfile.engine)

            self.importer = PgnImport(self.gamelist.chessfile.engine)
            for i, filename in enumerate(filenames):
                filename = unicode(filename)
                GLib.idle_add(self.progressbar0.set_fraction, i / float(len(filenames)))
                # GLib.idle_add(self.progressbar0.set_text, filename)
                if self.importer.cancel:
                    break
                if isinstance(filename, tuple):
                    info_link, pgn_link = filename
                    self.importer.do_import(pgn_link, info=info_link, progressbar=self.progressbar)
                else:
                    self.importer.do_import(filename, progressbar=self.progressbar)

            GLib.idle_add(self.progressbar.set_text, "Recreating indexes...")
            create_indexes(self.gamelist.chessfile.engine)

            self.gamelist.offset = 0
            self.gamelist.chessfile.build_where_tags("")
            self.gamelist.chessfile.build_where_bitboards(0, 0)
            self.gamelist.chessfile.build_query()
            self.gamelist.chessfile.update_count()
            self.gamelist.chessfile.update_count_stats()
            GLib.idle_add(self.gamelist.load_games)
            GLib.idle_add(self.emit, "chessfile_imported", self.gamelist.chessfile)
            GLib.idle_add(self.progress_dialog.hide)

        thread = threading.Thread(target=importing)
        thread.daemon = True
        thread.start()
コード例 #8
0
class ChatWindow(object):
    def __init__(self, widgets, connection):
        self.connection = connection
        self.window = None

        widgets["show_chat_button"].connect("clicked", self.showChat)
        connection.cm.connect("privateMessage", self.onPersonMessage)
        connection.connect("disconnected", self.onDisconnected)

        self.viewspanel = ViewsPanel(self.connection)
        self.channelspanel = ChannelsPanel(self.connection)
        self.infopanel = InfoPanel(self.connection)
        self.panels = [self.viewspanel, self.channelspanel, self.infopanel]
        self.viewspanel.connect('channel_content_Changed',
                                self.channelspanel.channel_Highlight, id)

    @idle_add
    def onDisconnected(self, conn):
        if self.window:
            self.window.hide()

    def showChat(self, *widget):
        if not self.window:
            self.initUi()
        self.window.show_all()
        self.window.present()

    def initUi(self):
        self.window = Gtk.Window()
        self.window.set_border_width(12)
        self.window.set_icon_name("pychess")
        self.window.set_title("PyChess - Internet Chess Chat")
        self.window.connect_after("delete-event",
                                  lambda w, e: w.hide() or True)

        uistuff.keepWindowSize("chat", self.window, defaultSize=(650, 400))

        self.dock = PyDockTop("icchat")
        self.dock.show()
        self.window.add(self.dock)

        leaf = self.dock.dock(self.viewspanel, CENTER, Gtk.Label(label="chat"),
                              "chat")
        leaf.setDockable(False)

        self.channelspanel.connect('conversationAdded',
                                   self.onConversationAdded)
        self.channelspanel.connect('conversationRemoved',
                                   self.onConversationRemoved)
        self.channelspanel.connect('conversationSelected',
                                   self.onConversationSelected)
        leaf.dock(self.channelspanel, WEST,
                  Gtk.Label(label=_("Conversations")), "conversations")

        leaf.dock(self.infopanel, EAST,
                  Gtk.Label(label=_("Conversation info")), "info")

        for panel in self.panels:
            panel.show_all()
            panel.start()

    def onConversationAdded(self, panel, grp_id, text, grp_type):
        chatView = ChatView()
        plus_channel = '+channel ' + str(grp_id)
        self.connection.cm.connection.client.run_command(plus_channel)
        for panel in self.panels:
            panel.addItem(grp_id, text, grp_type, chatView)

    def onConversationRemoved(self, panel, grp_id):
        minus_channel = '-channel ' + str(grp_id)
        self.connection.cm.connection.client.run_command(minus_channel)
        for panel in self.panels:
            panel.removeItem(grp_id)

    def onConversationSelected(self, panel, grp_id):
        for panel in self.panels:
            panel.selectItem(grp_id)

    @idle_add
    def onPersonMessage(self, cm, name, title, isadmin, text):
        console_active = False
        for window in Gtk.Window.list_toplevels():
            if window.is_active():
                window_icon_name = window.get_icon_name()
                if window_icon_name is not None and "pychess" in window_icon_name:
                    console_active = True
                    break

        if self.connection.bm.isPlaying() or console_active:
            if not self.window:
                self.initUi()
        else:
            self.showChat()
            self.window.set_urgency_hint(True)
            self.initial_focus_id = self.window.connect(
                "focus-in-event", self.on_initial_focus_in)

    def on_initial_focus_in(self, widget, event):
        self.window.set_urgency_hint(False)
        self.window.disconnect(self.initial_focus_id)
        return False

    def openChatWithPlayer(self, name):
        self.showChat()
        self.window.get_window().raise_()
        cm = self.connection.cm
        self.onPersonMessage(cm, name, "", False, "")
        self.channelspanel.onPersonMessage(cm, name, "", False, "")
コード例 #9
0
ファイル: __init__.py プロジェクト: bboutkov/pychess
class Database(GObject.GObject, Perspective):
    __gsignals__ = {
        'chessfile_opened0': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_opened': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_closed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'chessfile_imported': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "database", _("Database"))
        self.widgets = gamewidget.getWidgets()
        self.chessfile = None
        self.chessfiles = []
        self.gamelists = []
        self.filter_panels = []
        self.notebooks = {}
        self.connect("chessfile_opened0", self.on_chessfile_opened0)

    @property
    def gamelist(self):
        if self.chessfile is None:
            return None
        else:
            return self.gamelists[self.chessfiles.index(self.chessfile)]

    @property
    def filter_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.filter_panels[self.chessfiles.index(self.chessfile)]

    def create_toolbuttons(self):
        self.import_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CONVERT)
        self.import_button.set_tooltip_text(_("Import PGN file"))
        self.import_button.connect("clicked", self.on_import_clicked)

        self.close_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CLOSE)
        self.close_button.set_tooltip_text(_("Close"))
        self.close_button.connect("clicked", self.close)

    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)

        mainwindow = gamewidget.getWidgets()["main_window"]
        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(None,
                                            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.close_button])

        self.switcher_panel.connect("chessfile_switched", self.on_chessfile_switched)

    def set_sensitives(self, on):
        self.import_button.set_sensitive(on)
        self.widgets["import_chessfile"].set_sensitive(on)
        self.widgets["import_endgame_nl"].set_sensitive(on)
        self.widgets["import_twic"].set_sensitive(on)

    def open_chessfile(self, filename):
        if self.chessfile is None:
            self.init_layout()

        perspective_manager.activate_perspective("database")

        self.progress_dialog.set_title(_("Open"))
        self.progressbar0.hide()
        self.progressbar1.show()
        self.progressbar1.set_text("Importing game headers...")
        self.spinner.show()
        self.spinner.start()

        def opening():
            if filename.endswith(".pgn"):
                chessfile = pgn.load(protoopen(filename), self.progressbar1)
            elif filename.endswith(".epd"):
                chessfile = epd.load(protoopen(filename))
            elif filename.endswith(".fen"):
                chessfile = fen.load(protoopen(filename))
            else:
                chessfile = None

            GLib.idle_add(self.spinner.stop)
            GLib.idle_add(self.progress_dialog.hide)
            if chessfile is not None:
                self.chessfile = chessfile
                self.chessfiles.append(chessfile)
                GLib.idle_add(self.emit, "chessfile_opened0", chessfile)

        thread = threading.Thread(target=opening)
        thread.daemon = True
        thread.start()

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_chessfile_opened0(self, persp, chessfile):
        gamelist = GameList(self)
        self.gamelists.append(gamelist)
        opening_tree_panel = OpeningTreePanel(self)
        filter_panel = FilterPanel(self)
        self.filter_panels.append(filter_panel)
        preview_panel = PreviewPanel(self)

        self.notebooks["gamelist"].append_page(gamelist.box)
        self.notebooks["opening_tree"].append_page(opening_tree_panel.box)
        self.notebooks["filter"].append_page(filter_panel.box)
        self.notebooks["preview"].append_page(preview_panel.box)

        self.on_chessfile_switched(None, self.chessfile)

        gamelist.load_games()
        opening_tree_panel.update_tree(load_games=False)

        self.set_sensitives(True)
        self.emit("chessfile_opened", chessfile)

    def close(self, widget):
        i = self.chessfiles.index(self.chessfile)
        if self.chessfile.path is not None:
            self.notebooks["gamelist"].remove_page(i)
            self.notebooks["opening_tree"].remove_page(i)
            self.notebooks["filter"].remove_page(i)
            self.notebooks["preview"].remove_page(i)
            del self.gamelists[i]
            del self.filter_panels[i]
            del self.chessfiles[i]
            self.chessfile.close()

        if len(self.chessfiles) == 0:
            self.set_sensitives(False)
            perspective_manager.disable_perspective("database")

        self.emit("chessfile_closed")

    def on_chessfile_switched(self, switcher, chessfile):
        self.chessfile = chessfile
        i = self.chessfiles.index(chessfile)

        self.notebooks["gamelist"].set_current_page(i)
        self.notebooks["opening_tree"].set_current_page(i)
        self.notebooks["filter"].set_current_page(i)
        self.notebooks["preview"].set_current_page(i)

    def on_import_endgame_nl(self):
        self.do_import(JvR)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_twic(self):
        LATEST = get_latest_twic()
        if LATEST is None:
            return

        html = "http://www.theweekinchess.com/html/twic%s.html"
        twic = []

        pgn = "https://raw.githubusercontent.com/rozim/ChessData/master/Twic/fix-twic%s.pgn"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(210, 920):
            twic.append((html % i, pgn % i))

        pgn = "http://www.theweekinchess.com/zips/twic%sg.zip"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(920, LATEST + 1):
            twic.append((html % i, pgn % i))

        twic.append((html % LATEST, pgn % LATEST))

        # import limited to latest twic .pgn for now
        twic = twic[-1:]

        self.do_import(twic)
        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            _("Open chess file"), None, 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()

    def do_import(self, filenames):
        self.progress_dialog.set_title(_("Import"))
        self.spinner.hide()
        if len(filenames) == 1:
            self.progressbar0.hide()
        else:
            self.progressbar0.show()
        self.progressbar1.show()
        self.progressbar1.set_text("Preparing to start import...")

        # @profile_me
        def importing():
            drop_indexes(self.chessfile.engine)

            self.importer = PgnImport(self.chessfile, append_pgn=True)
            for i, filename in enumerate(filenames):
                GLib.idle_add(self.progressbar0.set_fraction, i / float(len(filenames)))
                # GLib.idle_add(self.progressbar0.set_text, filename)
                if self.importer.cancel:
                    break
                if isinstance(filename, tuple):
                    info_link, pgn_link = filename
                    self.importer.do_import(pgn_link, info=info_link, progressbar=self.progressbar1)
                else:
                    self.importer.do_import(filename, progressbar=self.progressbar1)

            GLib.idle_add(self.progressbar1.set_text, "Recreating indexes...")

            # .sqlite
            create_indexes(self.chessfile.engine)

            # .scout
            self.chessfile.init_scoutfish()

            # .bin
            self.chessfile.init_chess_db()

            self.chessfile.set_tag_filter(None)
            self.chessfile.set_fen_filter(None)
            self.chessfile.set_scout_filter(None)
            GLib.idle_add(self.gamelist.load_games)
            GLib.idle_add(self.emit, "chessfile_imported", self.chessfile)
            GLib.idle_add(self.progress_dialog.hide)

        thread = threading.Thread(target=importing)
        thread.daemon = True
        thread.start()

    def create_database(self):
        dialog = Gtk.FileChooserDialog(
            _("Create New Pgn Database"), None, 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(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()
コード例 #10
0
class Database(GObject.GObject, Perspective):
    __gsignals__ = {
        'chessfile_opened0': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_opened': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_closed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'chessfile_imported':
        (GObject.SignalFlags.RUN_FIRST, None, (object, )),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "database", _("Database"))
        self.widgets = gamewidget.getWidgets()
        self.chessfile = None
        self.chessfiles = []
        self.gamelists = []
        self.filter_panels = []
        self.notebooks = {}
        self.connect("chessfile_opened0", self.on_chessfile_opened0)

    @property
    def gamelist(self):
        if self.chessfile is None:
            return None
        else:
            return self.gamelists[self.chessfiles.index(self.chessfile)]

    @property
    def filter_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.filter_panels[self.chessfiles.index(self.chessfile)]

    def create_toolbuttons(self):
        self.import_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CONVERT)
        self.import_button.set_tooltip_text(_("Import PGN file"))
        self.import_button.connect("clicked", self.on_import_clicked)

        self.save_as_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.set_tooltip_text(_("Save to PGN file as..."))
        self.save_as_button.connect("clicked", self.on_save_as_clicked)

        self.close_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CLOSE)
        self.close_button.set_tooltip_text(_("Close"))
        self.close_button.connect("clicked", self.close)

    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)

    def set_sensitives(self, on):
        self.import_button.set_sensitive(on)
        self.widgets["import_chessfile"].set_sensitive(on)
        self.widgets["database_save_as"].set_sensitive(on)
        self.widgets["import_endgame_nl"].set_sensitive(on)
        self.widgets["import_twic"].set_sensitive(on)

    def open_chessfile(self, filename):
        if self.chessfile is None:
            self.init_layout()

        perspective_manager.activate_perspective("database")

        self.progress_dialog.set_title(_("Open"))
        self.progressbar0.hide()
        self.progressbar1.show()
        self.progressbar1.set_text("Importing game headers...")
        self.spinner.show()
        self.spinner.start()

        def opening():
            if filename.endswith(".pgn"):
                chessfile = pgn.load(protoopen(filename), self.progressbar1)
            elif filename.endswith(".epd"):
                chessfile = epd.load(protoopen(filename))
            elif filename.endswith(".fen"):
                chessfile = fen.load(protoopen(filename))
            else:
                chessfile = None

            GLib.idle_add(self.spinner.stop)
            GLib.idle_add(self.progress_dialog.hide)
            if chessfile is not None:
                self.chessfile = chessfile
                self.chessfiles.append(chessfile)
                GLib.idle_add(self.emit, "chessfile_opened0", chessfile)

        thread = threading.Thread(target=opening)
        thread.daemon = True
        thread.start()

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_chessfile_opened0(self, persp, chessfile):
        gamelist = GameList(self)
        self.gamelists.append(gamelist)
        opening_tree_panel = OpeningTreePanel(self)
        filter_panel = FilterPanel(self)
        self.filter_panels.append(filter_panel)
        preview_panel = PreviewPanel(self)

        self.notebooks["gamelist"].append_page(gamelist.box)
        self.notebooks["opening_tree"].append_page(opening_tree_panel.box)
        self.notebooks["filter"].append_page(filter_panel.box)
        self.notebooks["preview"].append_page(preview_panel.box)

        self.on_chessfile_switched(None, self.chessfile)

        gamelist.load_games()
        opening_tree_panel.update_tree(load_games=False)

        self.set_sensitives(True)
        self.emit("chessfile_opened", chessfile)

    def close(self, widget):
        i = self.chessfiles.index(self.chessfile)
        if self.chessfile.path is not None:
            self.notebooks["gamelist"].remove_page(i)
            self.notebooks["opening_tree"].remove_page(i)
            self.notebooks["filter"].remove_page(i)
            self.notebooks["preview"].remove_page(i)
            del self.gamelists[i]
            del self.filter_panels[i]
            del self.chessfiles[i]
            self.chessfile.close()

        if len(self.chessfiles) == 0:
            self.set_sensitives(False)
            perspective_manager.disable_perspective("database")

        self.emit("chessfile_closed")

    def on_chessfile_switched(self, switcher, chessfile):
        self.chessfile = chessfile
        i = self.chessfiles.index(chessfile)

        self.notebooks["gamelist"].set_current_page(i)
        self.notebooks["opening_tree"].set_current_page(i)
        self.notebooks["filter"].set_current_page(i)
        self.notebooks["preview"].set_current_page(i)

    def on_import_endgame_nl(self):
        self.do_import(JvR)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_twic(self):
        LATEST = get_latest_twic()
        if LATEST is None:
            return

        html = "http://www.theweekinchess.com/html/twic%s.html"
        twic = []

        pgn = "https://raw.githubusercontent.com/rozim/ChessData/master/Twic/fix-twic%s.pgn"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(210, 920):
            twic.append((html % i, pgn % i))

        pgn = "http://www.theweekinchess.com/zips/twic%sg.zip"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(920, LATEST + 1):
            twic.append((html % i, pgn % i))

        twic.append((html % LATEST, pgn % LATEST))

        # import limited to latest twic .pgn for now
        twic = twic[-1:]

        self.do_import(twic)
        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_save_as_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            "", 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

    def save_records(self, records, to_file):
        f = self.chessfile.handle
        for i, rec in enumerate(records):
            offs = rec["Offset"]

            f.seek(offs)
            game = ''
            for line in f:
                if line.startswith('[Event "'):
                    if game:
                        break  # Second one, start of next game
                    else:
                        game = line  # First occurence
                elif game:
                    game += line
            to_file.write(game)

    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()

    def do_import(self, filenames):
        self.progress_dialog.set_title(_("Import"))
        self.spinner.hide()
        if len(filenames) == 1:
            self.progressbar0.hide()
        else:
            self.progressbar0.show()
        self.progressbar1.show()
        self.progressbar1.set_text("Preparing to start import...")

        # @profile_me
        def importing():
            drop_indexes(self.chessfile.engine)

            self.importer = PgnImport(self.chessfile, append_pgn=True)
            for i, filename in enumerate(filenames):
                GLib.idle_add(self.progressbar0.set_fraction,
                              i / float(len(filenames)))
                # GLib.idle_add(self.progressbar0.set_text, filename)
                if self.importer.cancel:
                    break
                if isinstance(filename, tuple):
                    info_link, pgn_link = filename
                    self.importer.do_import(pgn_link,
                                            info=info_link,
                                            progressbar=self.progressbar1)
                else:
                    self.importer.do_import(filename,
                                            progressbar=self.progressbar1)

            GLib.idle_add(self.progressbar1.set_text, "Recreating indexes...")

            # .sqlite
            create_indexes(self.chessfile.engine)

            # .scout
            self.chessfile.init_scoutfish()

            # .bin
            self.chessfile.init_chess_db()

            self.chessfile.set_tag_filter(None)
            self.chessfile.set_fen_filter(None)
            self.chessfile.set_scout_filter(None)
            GLib.idle_add(self.gamelist.load_games)
            GLib.idle_add(self.emit, "chessfile_imported", self.chessfile)
            GLib.idle_add(self.progress_dialog.hide)

        thread = threading.Thread(target=importing)
        thread.daemon = True
        thread.start()

    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()
コード例 #11
0
ファイル: __init__.py プロジェクト: teacoffee2017/pychess
class Learn(GObject.GObject, Perspective):
    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "learn", _("Learn"))
        self.always_on = True

        self.dockLocation = addUserConfigPrefix("pydock-learn.xml")
        self.first_run = True

    def create_toolbuttons(self):
        def on_exit_clicked(button):
            perspective_manager.disable_perspective("learn")

        self.exit_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_QUIT)
        self.exit_button.set_tooltip_text(_("Quit Learning"))
        self.exit_button.set_label("exit")
        self.exit_button.connect("clicked", on_exit_clicked)

    def init_layout(self):
        perspective_manager.set_perspective_toolbuttons("learn", (self.exit_button, ))

        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("learn", perspective_widget)
        perspective_manager.set_perspective_menuitems("learn", self.menuitems)

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

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

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

        self.docks["learnhome"] = (Gtk.Label(label="learnhome"), self.notebooks["learnhome"], 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["learnhome"][1], CENTER, self.docks["learnhome"][0], "learnhome")
            leaf.setDockable(False)

            leaf.dock(self.docks["PuzzlesPanel"][1], WEST, self.docks["PuzzlesPanel"][0], "PuzzlesPanel")
            leaf = leaf.dock(self.docks["LecturesPanel"][1], SOUTH, self.docks["LecturesPanel"][0], "LecturesPanel")
            leaf = leaf.dock(self.docks["LessonsPanel"][1], SOUTH, self.docks["LessonsPanel"][0], "LessonsPanel")
            leaf.dock(self.docks["EndgamesPanel"][1], SOUTH, self.docks["EndgamesPanel"][0], "EndgamesPanel")

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

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

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

        log.debug("Learn.__init__: finished")

    def activate(self):
        if self.first_run:
            self.init_layout()
            self.first_run = False

        learn_home = Gtk.Box()
        learn_home.add(Gtk.Label("Practice! Practice! Practice!"))
        learn_home.show_all()

        if not self.first_run:
            self.notebooks["learnhome"].remove_page(-1)
        self.notebooks["learnhome"].append_page(learn_home)

        self.panels = [panel.Sidepanel().load(self) for panel in self.sidePanels]

        for panel, instance in zip(self.sidePanels, self.panels):
            if not self.first_run:
                self.notebooks[panel.__name__].remove_page(-1)
            self.notebooks[panel.__name__].append_page(instance)
            instance.show()

        perspective_manager.activate_perspective("learn")
コード例 #12
0
ファイル: __init__.py プロジェクト: leogregianin/pychess
class FICS(GObject.GObject, Perspective):
    __gsignals__ = {
        'logout': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'autoLogout': (GObject.SignalFlags.RUN_FIRST, None, ()),
    }

    def __init__(self):
        log.debug("FICS.__init__: starting")
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "fics", _("ICS"))
        self.dockLocation = addUserConfigPrefix("pydock-fics.xml")
        self.first_run = True

    def create_toolbuttons(self):
        def on_logoff_clicked(button):
            self.emit("logout")
            self.close()

        self.logoff_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_DISCONNECT)
        self.logoff_button.set_tooltip_text(_("Log Off"))
        self.logoff_button.set_label("logoff")
        self.logoff_button.connect("clicked", on_logoff_clicked)

        def on_minute_1_clicked(button):
            self.connection.client.run_command("1-minute")

        def on_minute_3_clicked(button):
            self.connection.client.run_command("3-minute")

        def on_minute_5_clicked(button):
            self.connection.client.run_command("5-minute")

        def on_minute_15_clicked(button):
            self.connection.client.run_command("15-minute")

        def on_minute_25_clicked(button):
            self.connection.client.run_command("25-minute")

        def on_chess960_clicked(button):
            self.connection.client.run_command("chess960")

        self.minute_1_button = Gtk.ToggleToolButton()
        self.minute_1_button.set_label("1")
        self.minute_1_button.set_tooltip_text(_("New game from 1-minute playing pool"))
        self.minute_1_button.connect("clicked", on_minute_1_clicked)

        self.minute_3_button = Gtk.ToggleToolButton()
        self.minute_3_button.set_label("3")
        self.minute_3_button.set_tooltip_text(_("New game from 3-minute playing pool"))
        self.minute_3_button.connect("clicked", on_minute_3_clicked)

        self.minute_5_button = Gtk.ToggleToolButton()
        self.minute_5_button.set_label("5")
        self.minute_5_button.set_tooltip_text(_("New game from 5-minute playing pool"))
        self.minute_5_button.connect("clicked", on_minute_5_clicked)

        self.minute_15_button = Gtk.ToggleToolButton()
        self.minute_15_button.set_label("15")
        self.minute_15_button.set_tooltip_text(_("New game from 15-minute playing pool"))
        self.minute_15_button.connect("clicked", on_minute_15_clicked)

        self.minute_25_button = Gtk.ToggleToolButton()
        self.minute_25_button.set_label("25")
        self.minute_25_button.set_tooltip_text(_("New game from 25-minute playing pool"))
        self.minute_25_button.connect("clicked", on_minute_25_clicked)

        self.chess960_button = Gtk.ToggleToolButton()
        self.chess960_button.set_label("960")
        self.chess960_button.set_tooltip_text(_("New game from Chess960 playing pool"))
        self.chess960_button.connect("clicked", on_chess960_clicked)

    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("fics", perspective_widget)
        perspective_manager.set_perspective_menuitems("fics", self.menuitems)

        self.infobar = InfoBarNotebook("fics_lounge_infobar")
        self.infobar.hide()
        perspective_widget.pack_start(self.infobar, False, False, 0)

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

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

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

        self.load_from_xml()

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

            console_leaf = leaf.dock(self.docks["ConsolePanel"][1], SOUTH, self.docks["ConsolePanel"][0], "ConsolePanel")
            console_leaf.dock(self.docks["NewsPanel"][1], CENTER, self.docks["NewsPanel"][0], "NewsPanel")

            seek_leaf = leaf.dock(self.docks["SeekListPanel"][1], WEST, self.docks["SeekListPanel"][0], "SeekListPanel")
            seek_leaf.dock(self.docks["SeekGraphPanel"][1], CENTER, self.docks["SeekGraphPanel"][0], "SeekGraphPanel")
            seek_leaf.dock(self.docks["PlayerListPanel"][1], CENTER, self.docks["PlayerListPanel"][0], "PlayerListPanel")
            seek_leaf.dock(self.docks["GameListPanel"][1], CENTER, self.docks["GameListPanel"][0], "GameListPanel")
            seek_leaf.dock(self.docks["ArchiveListPanel"][1], CENTER, self.docks["ArchiveListPanel"][0], "ArchiveListPanel")

            leaf = leaf.dock(self.docks["ChatPanel"][1], SOUTH, self.docks["ChatPanel"][0], "ChatPanel")
            # leaf.dock(self.docks["LecturesPanel"][1], CENTER, self.docks["LecturesPanel"][0], "LecturesPanel")

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

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

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

        log.debug("FICS.__init__: finished")

    def open_lounge(self, connection, helperconn, host):
        if self.first_run:
            self.init_layout()

        self.connection = connection
        self.helperconn = helperconn
        self.host = host

        self.finger_sent = False
        self.messages = []
        self.players = []
        self.game_cids = {}

        self.widgets = uistuff.GladeWidgets("fics_lounge.glade")
        self.widgets["fics_lounge"].hide()

        fics_home = self.widgets["fics_home"]
        self.widgets["fics_lounge_content_hbox"].remove(fics_home)

        self.archive_list = self.widgets["archiveListContent"]
        self.widgets["fics_panels_notebook"].remove(self.archive_list)

        self.games_list = self.widgets["gamesListContent"]
        self.widgets["fics_panels_notebook"].remove(self.games_list)

        self.news_list = self.widgets["news"]
        self.widgets["fics_home"].remove(self.news_list)

        self.players_list = self.widgets["playersListContent"]
        self.widgets["fics_panels_notebook"].remove(self.players_list)

        self.seek_graph = self.widgets["seekGraphContent"]
        self.widgets["fics_panels_notebook"].remove(self.seek_graph)

        self.seek_list = self.widgets["seekListContent"]
        self.widgets["fics_panels_notebook"].remove(self.seek_list)

        self.seek_challenge = SeekChallengeSection(self)

        def on_autoLogout(alm):
            self.emit("autoLogout")
            self.close()

        self.connection.alm.connect("logOut", on_autoLogout)
        self.connection.connect("disconnected", lambda connection: self.close())
        self.connection.connect("error", self.on_connection_error)
        if self.connection.isRegistred():
            numtimes = conf.get("numberOfTimesLoggedInAsRegisteredUser") + 1
            conf.set("numberOfTimesLoggedInAsRegisteredUser", numtimes)
        self.connection.em.connect("onCommandNotFound", lambda em, cmd: log.error(
            "Fics answered '%s': Command not found" % cmd))
        self.connection.bm.connect("playGameCreated", self.onPlayGameCreated)
        self.connection.bm.connect("obsGameCreated", self.onObserveGameCreated)
        self.connection.bm.connect("exGameCreated", self.onObserveGameCreated)
        self.connection.fm.connect("fingeringFinished", self.onFinger)
        # the rest of these relay server messages to the lounge infobar
        self.connection.bm.connect("tooManySeeks", self.tooManySeeks)
        self.connection.bm.connect("nonoWhileExamine", self.nonoWhileExamine)
        self.connection.bm.connect("matchDeclined", self.matchDeclined)
        self.connection.bm.connect("player_on_censor", self.player_on_censor)
        self.connection.bm.connect("player_on_noplay", self.player_on_noplay)
        self.connection.bm.connect("req_not_fit_formula", self.req_not_fit_formula)
        self.connection.glm.connect("seek-updated", self.on_seek_updated)
        self.connection.glm.connect("our-seeks-removed", self.our_seeks_removed)
        self.connection.cm.connect("arrivalNotification", self.onArrivalNotification)
        self.connection.cm.connect("departedNotification", self.onDepartedNotification)

        def get_top_games():
            if perspective_manager.current_perspective == self:
                self.connection.client.run_command("games *19")
            return True

        if self.connection.ICC:
            self.event_id = GLib.timeout_add_seconds(5, get_top_games)

        for user in self.connection.notify_users:
            user = self.connection.players.get(user)
            self.user_from_notify_list_is_present(user)

        self.userinfo = UserInfoSection(self.widgets, self.connection, self.host, self)
        if not self.first_run:
            self.notebooks["ficshome"].remove_page(-1)
        self.notebooks["ficshome"].append_page(fics_home)

        self.panels = [panel.Sidepanel().load(self.widgets, self.connection, self) for panel in self.sidePanels]

        for panel, instance in zip(self.sidePanels, self.panels):
            if not self.first_run:
                self.notebooks[panel_name(panel.__name__)].remove_page(-1)
            self.notebooks[panel_name(panel.__name__)].append_page(instance)
            instance.show()

        tool_buttons = [self.logoff_button, ]
        self.quick_seek_buttons = []
        if self.connection.ICC:
            self.quick_seek_buttons = [self.minute_1_button, self.minute_3_button, self.minute_5_button,
                                       self.minute_15_button, self.minute_25_button, self.chess960_button]
            tool_buttons += self.quick_seek_buttons
        perspective_manager.set_perspective_toolbuttons("fics", tool_buttons)

        if self.first_run:
            self.first_run = False

        # After all panel is set up we can push initial messages out
        self.connection.com.onConsoleMessage("", self.connection.ini_messages)

    def show(self):
        perspective_manager.activate_perspective("fics")

    def present(self):
        perspective_manager.activate_perspective("fics")

    def on_connection_error(self, connection, error):
        log.warning("FICS.on_connection_error: %s" % repr(error))
        self.close()

    def close(self):
        try:
            self.widgets = None
        except TypeError:
            pass
        except AttributeError:
            pass
        perspective_manager.disable_perspective("fics")

    def onPlayGameCreated(self, bm, ficsgame):
        log.debug("FICS.onPlayGameCreated: %s" % ficsgame)

        for message in self.messages:
            message.dismiss()
        del self.messages[:]

        if self.connection.ICC:
            for button in self.quick_seek_buttons:
                button.set_active(False)

        timemodel = TimeModel(ficsgame.minutes * 60, ficsgame.inc)

        gamemodel = ICGameModel(self.connection, ficsgame, timemodel)
        gamemodel.connect("game_started", self.onGameModelStarted, ficsgame)

        wplayer, bplayer = ficsgame.wplayer, ficsgame.bplayer

        # We start
        if wplayer.name.lower() == self.connection.getUsername().lower():
            player0tup = (LOCAL, Human,
                          (WHITE, wplayer.long_name(), wplayer.name,
                           wplayer.getRatingForCurrentGame()),
                          wplayer.long_name())
            player1tup = (REMOTE, ICPlayer, (
                gamemodel, bplayer.name, ficsgame.gameno, BLACK,
                bplayer.long_name(), bplayer.getRatingForCurrentGame()),
                bplayer.long_name())

        # She starts
        else:
            player1tup = (LOCAL, Human,
                          (BLACK, bplayer.long_name(), bplayer.name,
                           bplayer.getRatingForCurrentGame()),
                          bplayer.long_name())
            player0tup = (REMOTE, ICPlayer, (
                gamemodel, wplayer.name, ficsgame.gameno, WHITE,
                wplayer.long_name(), wplayer.getRatingForCurrentGame()),
                wplayer.long_name())

        perspective = perspective_manager.get_perspective("games")
        if not ficsgame.board.fen:
            create_task(perspective.generalStart(gamemodel, player0tup, player1tup))
        else:
            create_task(perspective.generalStart(gamemodel, player0tup, player1tup, (
                StringIO(ficsgame.board.fen), fen, 0, -1)))

    def onGameModelStarted(self, gamemodel, ficsgame):
        self.connection.bm.onGameModelStarted(ficsgame.gameno)

    def onObserveGameCreated(self, bm, ficsgame):
        log.debug("FICS.onObserveGameCreated: %s" % ficsgame)

        timemodel = TimeModel(ficsgame.minutes * 60, ficsgame.inc)

        gamemodel = ICGameModel(self.connection, ficsgame, timemodel)
        gamemodel.connect("game_started", self.onGameModelStarted, ficsgame)

        # The players need to start listening for moves IN this method if they
        # want to be noticed of all moves the FICS server sends us from now on
        wplayer, bplayer = ficsgame.wplayer, ficsgame.bplayer

        player0tup = (REMOTE, ICPlayer, (
            gamemodel, wplayer.name, ficsgame.gameno, WHITE,
            wplayer.long_name(), wplayer.getRatingForCurrentGame()),
            wplayer.long_name())
        player1tup = (REMOTE, ICPlayer, (
            gamemodel, bplayer.name, ficsgame.gameno, BLACK,
            bplayer.long_name(), bplayer.getRatingForCurrentGame()),
            bplayer.long_name())

        perspective = perspective_manager.get_perspective("games")
        create_task(perspective.generalStart(gamemodel, player0tup, player1tup, (
            StringIO(ficsgame.board.pgn), pgn, 0, -1)))

        if ficsgame.relation == IC_POS_OBSERVING_EXAMINATION:
            if 1:  # int(self.connection.lvm.variablesBackup["kibitz"]) == 0:
                self.connection.cm.whisper(_(
                    "You have to set kibitz on to see bot messages here."))
            self.connection.fm.finger(bplayer.name)
            self.connection.fm.finger(wplayer.name)
        elif ficsgame.relation == IC_POS_EXAMINATING:
            gamemodel.examined = True
        if not self.connection.ICC:
            allob = 'allob ' + str(ficsgame.gameno)
            gamemodel.connection.client.run_command(allob)

    def onFinger(self, fm, finger):
        titles = finger.getTitles()
        if titles is not None:
            name = finger.getName()
            player = self.connection.players.get(name)
            for title in titles:
                player.titles.add(TITLES[title])

    def tooManySeeks(self, bm):
        label = Gtk.Label(label=_(
            "You may only have 3 outstanding seeks at the same time. If you want \
            to add a new seek you must clear your currently active seeks. Clear your seeks?"))
        label.set_width_chars(80)
        label.props.xalign = 0
        label.set_line_wrap(True)

        def response_cb(infobar, response, message):
            if response == Gtk.ResponseType.YES:
                self.connection.client.run_command("unseek")
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.QUESTION, label, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_YES,
                                                Gtk.ResponseType.YES))
        message.add_button(InfoBarMessageButton(Gtk.STOCK_NO,
                                                Gtk.ResponseType.NO))
        self.messages.append(message)
        self.infobar.push_message(message)

    def nonoWhileExamine(self, bm):
        label = Gtk.Label(_("You can't touch this! You are examining a game."))

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, label, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def matchDeclined(self, bm, player):
        text = _(" has declined your offer for a match")
        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def player_on_censor(self, bm, player):
        text = _(" is censoring you")
        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def player_on_noplay(self, bm, player):
        text = _(" noplay listing you")
        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def req_not_fit_formula(self, bm, player, formula):
        content = get_infobarmessage_content2(
            player, _(" uses a formula not fitting your match request:"),
            formula)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def on_seek_updated(self, glm, message_text):
        if "manual accept" in message_text:
            message_text.replace("to manual accept", _("to manual accept"))
        elif "automatic accept" in message_text:
            message_text.replace("to automatic accept",
                                 _("to automatic accept"))
        if "rating range now" in message_text:
            message_text.replace("rating range now", _("rating range now"))
        label = Gtk.Label(label=_("Seek updated") + ": " + message_text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, label, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def our_seeks_removed(self, glm):
        label = Gtk.Label(label=_("Your seeks have been removed"))

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, label, response_cb)
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def _connect_to_player_changes(self, player):
        player.connect("ratings_changed", self._replace_notification_message, player)
        player.connect("notify::titles", self._replace_notification_message, None, player)

    def onArrivalNotification(self, cm, player):
        log.debug("%s" % player,
                  extra={"task": (self.connection.username,
                                  "onArrivalNotification")})
        self._add_notification_message(player, _(" has arrived"), chat=True, replace=True)
        if player not in self.players:
            self.players.append(player)
            self._connect_to_player_changes(player)

    def onDepartedNotification(self, cm, player):
        self._add_notification_message(player, _(" has departed"), replace=True)

    def user_from_notify_list_is_present(self, player):
        self._add_notification_message(player, _(" is present"), chat=True, replace=True)
        if player not in self.players:
            self.players.append(player)
            self._connect_to_player_changes(player)

    def _add_notification_message(self, player, text, chat=False, replace=False):
        if replace:
            for message in self.messages:
                if isinstance(message, PlayerNotificationMessage) and message.player == player:
                    message.dismiss()

        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            if response == 1:
                if player is None:
                    return
                self.chat.openChatWithPlayer(player.name)
            if response == 2:
                if player is None:
                    return
                self.connection.client.run_command("follow %s" % player.name)
            message.dismiss()
            #             self.messages.remove(message)
            return False

        message = PlayerNotificationMessage(Gtk.MessageType.INFO, content,
                                            response_cb, player, text)
        if chat:
            message.add_button(InfoBarMessageButton(_("Chat"), 1))
            message.add_button(InfoBarMessageButton(_("Follow"), 2))
        message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE,
                                                Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def _replace_notification_message(self, obj, prop, rating_type, player):
        log.debug("%s %s" % (repr(obj), player),
                  extra={"task": (self.connection.username,
                                  "_replace_notification_message")})
        for message in self.messages:
            if isinstance(message, PlayerNotificationMessage) and \
                    message.player == player:
                message.update_content(get_infobarmessage_content(
                    player, message.text))
        return False
コード例 #13
0
class Learn(GObject.GObject, Perspective):
    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "learn", _("Learn"))
        self.always_on = True

        self.dockLocation = addUserConfigPrefix("pydock-learn.xml")
        self.first_run = True

    def create_toolbuttons(self):
        def on_exit_clicked(button):
            perspective_manager.disable_perspective("learn")

        self.exit_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_QUIT)
        self.exit_button.set_tooltip_text(_("Quit Learning"))
        self.exit_button.set_label("exit")
        self.exit_button.connect("clicked", on_exit_clicked)

    def init_layout(self):
        perspective_manager.set_perspective_toolbuttons(
            "learn", (self.exit_button, ))

        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("learn", perspective_widget)
        perspective_manager.set_perspective_menuitems("learn", self.menuitems)

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

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

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

        self.docks["learnhome"] = (Gtk.Label(label="learnhome"),
                                   self.notebooks["learnhome"], 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["learnhome"][1], CENTER,
                                  self.docks["learnhome"][0], "learnhome")
            leaf.setDockable(False)

            leaf.dock(self.docks["PuzzlesPanel"][1], WEST,
                      self.docks["PuzzlesPanel"][0], "PuzzlesPanel")
            leaf = leaf.dock(self.docks["LecturesPanel"][1], SOUTH,
                             self.docks["LecturesPanel"][0], "LecturesPanel")
            leaf = leaf.dock(self.docks["LessonsPanel"][1], SOUTH,
                             self.docks["LessonsPanel"][0], "LessonsPanel")
            leaf.dock(self.docks["EndgamesPanel"][1], SOUTH,
                      self.docks["EndgamesPanel"][0], "EndgamesPanel")

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

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

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

        log.debug("Learn.__init__: finished")

    def activate(self):
        if self.first_run:
            self.init_layout()
            self.first_run = False

        learn_home = Gtk.Box()
        learn_home.add(Gtk.Label("Practice! Practice! Practice!"))
        learn_home.show_all()

        if not self.first_run:
            self.notebooks["learnhome"].remove_page(-1)
        self.notebooks["learnhome"].append_page(learn_home)

        self.panels = [
            panel.Sidepanel().load(self) for panel in self.sidePanels
        ]

        for panel, instance in zip(self.sidePanels, self.panels):
            if not self.first_run:
                self.notebooks[panel.__name__].remove_page(-1)
            self.notebooks[panel.__name__].append_page(instance)
            instance.show()

        perspective_manager.activate_perspective("learn")
コード例 #14
0
ファイル: __init__.py プロジェクト: bernardosulzbach/pychess
class Games(GObject.GObject, Perspective):
    __gsignals__ = {
        'gmwidg_created': (GObject.SignalFlags.RUN_FIRST, None, (object, ))
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "games", _("Games"))

        self.notebooks = {}
        self.first_run = True
        self.gamewidgets = set()
        self.gmwidg_cids = {}
        self.board_cids = {}
        self.notify_cids = defaultdict(list)

        self.key2gmwidg = {}
        self.key2cid = {}

        self.dock = None
        self.dockAlign = None
        self.dockLocation = addUserConfigPrefix("pydock.xml")

    @asyncio.coroutine
    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 set_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)

        if player0tup[0] == ARTIFICIAL and player1tup[0] == ARTIFICIAL:

            def emit_action(board, action, 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))

        # Starting
        if loaddata:
            try:
                uri, loader, gameno, position = loaddata
                gamemodel.loadAndStart(uri, loader, gameno, position)
                if position != gamemodel.ply:
                    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.hide()

        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))

    ################################################################################
    # Saving                                                                       #
    ################################################################################

    def saveGame(self, game, position=None):
        if not game.isChanged():
            return
        if game.uri and isWriteable(game.uri):
            self.saveGameSimple(game.uri, game, position=position)
        else:
            return self.saveGameAs(game, position=position)

    def saveGameSimple(self, uri, game, position=None):
        ending = os.path.splitext(uri)[1]
        if not ending:
            return
        saver = enddir[ending[1:]]
        game.save(uri, saver, append=False, position=position)

    def saveGamePGN(self, game):
        if game.practice_game:
            return True

        if conf.get("saveOwnGames", False) and not game.hasLocalPlayer():
            return True

        filename = conf.get("autoSaveFormat", "pychess")
        filename = filename.replace("#n1", game.tags["White"])
        filename = filename.replace("#n2", game.tags["Black"])
        filename = filename.replace("#y", "%s" % game.tags["Year"])
        filename = filename.replace("#m", "%s" % game.tags["Month"])
        filename = filename.replace("#d", "%s" % game.tags["Day"])
        pgn_path = conf.get("autoSavePath", os.path.expanduser("~")) + \
            "/" + filename + ".pgn"
        append = True
        try:
            if not os.path.isfile(pgn_path):
                # create new file
                with open(pgn_path, "w"):
                    pass
            base_offset = os.path.getsize(pgn_path)

            # save to .sqlite
            database_path = os.path.splitext(pgn_path)[0] + '.sqlite'
            database.save(database_path, game, base_offset)

            # save to .scout
            from pychess.Savers.pgn import scoutfish_path
            if scoutfish_path is not None:
                pgn_text = pgn.save(StringIO(), game)

                tmp = tempfile.NamedTemporaryFile(mode="w", delete=False)
                pgnfile = tmp.name
                with tmp.file as f:
                    f.write(pgn_text)

                # create new .scout from pgnfile we are importing
                args = [scoutfish_path, "make", pgnfile, "%s" % base_offset]
                output = subprocess.check_output(args, stderr=subprocess.STDOUT)

                # append it to our existing one
                if output.decode().find(u"Processing...done") > 0:
                    old_scout = os.path.splitext(pgn_path)[0] + '.scout'
                    new_scout = os.path.splitext(pgnfile)[0] + '.scout'

                    with open(old_scout, "ab") as file1, open(new_scout, "rb") as file2:
                        file1.write(file2.read())

            # TODO: do we realy want to update .bin ? It can be huge/slow!

            # save to .pgn
            game.save(pgn_path, pgn, append)

            return True
        except IOError:
            return False

    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.hide()
                    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.hide()
                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.hide()

                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.hide()
                continue

            break

        savedialog.destroy()
        return res

    ################################################################################
    # Closing                                                                      #
    ################################################################################
    def closeAllGames(self, gamewidgets):
        log.debug("Games.closeAllGames")
        response = None
        changedPairs = [(gmwidg, gmwidg.gamemodel) for gmwidg in gamewidgets
                        if gmwidg.gamemodel.isChanged()]
        if len(changedPairs) == 0:
            response = Gtk.ResponseType.OK

        elif len(changedPairs) == 1:
            response = self.closeGame(changedPairs[0][0])
        else:
            markup = "<big><b>" + ngettext("There is %d game with unsaved moves.",
                                           "There are %d games with unsaved moves.",
                                           len(changedPairs)) % len(changedPairs) + " " + \
                _("Save moves before closing?") + "</b></big>"

            for gmwidg, game in changedPairs:
                if not gmwidg.gamemodel.isChanged():
                    response = Gtk.ResponseType.OK
                else:
                    if conf.get("autoSave", False):
                        x = self.saveGamePGN(game)
                        if x:
                            response = Gtk.ResponseType.OK
                        else:
                            response = None
                            markup = "<b><big>" + _("Unable to save to configured file. \
                                                    Save the games before closing?") + "</big></b>"
                            break

            if response is None:
                widgets = GladeWidgets("saveGamesDialog.glade")
                dialog = widgets["saveGamesDialog"]
                heading = widgets["saveGamesDialogHeading"]
                saveLabel = widgets["saveGamesDialogSaveLabel"]
                treeview = widgets["saveGamesDialogTreeview"]

                heading.set_markup(markup)

                liststore = Gtk.ListStore(bool, str)
                treeview.set_model(liststore)
                renderer = Gtk.CellRendererToggle()
                renderer.props.activatable = True
                treeview.append_column(Gtk.TreeViewColumn("", renderer, active=0))
                treeview.append_column(Gtk.TreeViewColumn("",
                                                          Gtk.CellRendererText(),
                                                          text=1))
                for gmwidg, game in changedPairs:
                    liststore.append((True, "%s %s %s" % (game.players[0], _("vs."), game.players[1])))

                def callback(cell, path):
                    if path:
                        liststore[path][0] = not liststore[path][0]
                    saves = len(tuple(row for row in liststore if row[0]))
                    saveLabel.set_text(ngettext(
                        "_Save %d document", "_Save %d documents", saves) % saves)
                    saveLabel.set_use_underline(True)

                renderer.connect("toggled", callback)

                callback(None, None)

                while True:
                    response = dialog.run()
                    if response == Gtk.ResponseType.YES:
                        for i in range(len(liststore) - 1, -1, -1):
                            checked, name = liststore[i]
                            if checked:
                                cgmwidg, cgame = changedPairs[i]
                                if self.saveGame(cgame) == Gtk.ResponseType.ACCEPT:
                                    liststore.remove(liststore.get_iter((i, )))
                                    del changedPairs[i]
                                    if cgame.status in UNFINISHED_STATES:
                                        cgame.end(ABORTED, ABORTED_AGREEMENT)
                                    cgame.terminate()
                                    self.delGameWidget(cgmwidg)
                                else:
                                    break
                        else:
                            break
                    else:
                        break
                dialog.destroy()

        if response not in (Gtk.ResponseType.DELETE_EVENT,
                            Gtk.ResponseType.CANCEL):
            pairs = [(gmwidg, gmwidg.gamemodel) for gmwidg in gamewidgets]
            for gmwidg, game in pairs:
                if game.status in UNFINISHED_STATES:
                    game.end(ABORTED, ABORTED_AGREEMENT)
                game.terminate()
                if gmwidg.notebookKey in self.key2gmwidg:
                    self.delGameWidget(gmwidg)

        return response

    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", False):
                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()

            if len(self.gamewidgets) == 0:
                for widget in MENU_ITEMS:
                    gamewidget.getWidgets()[widget].set_property('sensitive', False)

        return response

    def delGameWidget(self, gmwidg):
        """ Remove the widget from the GUI after the game has been terminated """
        log.debug("Games.delGameWidget: starting %s" % repr(gmwidg))
        gmwidg.closed = True
        gmwidg.emit("closed")

        called_from_preferences = False
        window_list = Gtk.Window.list_toplevels()
        widgets = gamewidget.getWidgets()
        for window in window_list:
            if window.is_active() and window == widgets["preferences"]:
                called_from_preferences = True
                break

        pageNum = gmwidg.getPageNumber()
        headbook = self.getheadbook()

        if gmwidg.notebookKey in self.key2gmwidg:
            del self.key2gmwidg[gmwidg.notebookKey]

        if gmwidg.notebookKey in self.key2cid:
            headbook.disconnect(self.key2cid[gmwidg.notebookKey])
            del self.key2cid[gmwidg.notebookKey]

        headbook.remove_page(pageNum)
        for notebook in self.notebooks.values():
            notebook.remove_page(pageNum)

        if headbook.get_n_pages() == 1 and conf.get("hideTabs", False):
            self.show_tabs(False)

        if headbook.get_n_pages() == 0:
            if not called_from_preferences:
                # If the last (but not the designGW) gmwidg was closed
                # and we are FICS-ing, present the FICS lounge
                perspective_manager.disable_perspective("games")

        gmwidg._del()

    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("games", perspective_widget)

        self.notebooks = {"board": new_notebook("board"),
                          "buttons": new_notebook("buttons"),
                          "messageArea": new_notebook("messageArea")}
        self.main_notebook = self.notebooks["board"]
        for panel in self.sidePanels:
            self.notebooks[panel.__name__] = new_notebook(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"], 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["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(self.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()

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

        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)

    def getheadbook(self):
        if len(self.key2gmwidg) == 0:
            return None
        headbook = self.widget.get_children()[0].get_children()[0].get_child()
        # to help StoryText create widget description
        # headbook.get_tab_label_text = customGetTabLabelText
        return headbook

    def cur_gmwidg(self):
        if len(self.key2gmwidg) == 0:
            return None
        headbook = self.getheadbook()
        notebookKey = headbook.get_nth_page(headbook.get_current_page())
        return self.key2gmwidg[notebookKey]

    def customGetTabLabelText(self, child):
        gmwidg = self.key2gmwidg[child]
        return gmwidg.display_text

    def zoomToBoard(self, view_zoomed):
        if not self.notebooks["board"].get_parent():
            return
        if view_zoomed:
            self.notebooks["board"].get_parent().get_parent().zoomUp()
        else:
            self.notebooks["board"].get_parent().get_parent().zoomDown()

    def show_tabs(self, show):
        head = self.getheadbook()
        if head is None:
            return
        head.set_show_tabs(show)

    def tabsCallback(self, widget):
        head = self.getheadbook()
        if not head:
            return
        if head.get_n_pages() == 1:
            self.show_tabs(not conf.get("hideTabs", False))

    def attachGameWidget(self, gmwidg):
        log.debug("attachGameWidget: %s" % gmwidg)
        if self.first_run:
            self.init_layout()
            self.first_run = False
        perspective_manager.activate_perspective("games")

        gmwidg.panels = [panel.Sidepanel().load(gmwidg) for panel in self.sidePanels]
        self.key2gmwidg[gmwidg.notebookKey] = gmwidg
        headbook = self.getheadbook()

        headbook.append_page(gmwidg.notebookKey, gmwidg.tabcontent)
        gmwidg.notebookKey.show_all()

        if hasattr(headbook, "set_tab_reorderable"):
            headbook.set_tab_reorderable(gmwidg.notebookKey, True)

        def callback(notebook, gpointer, page_num, gmwidg):
            if notebook.get_nth_page(page_num) == gmwidg.notebookKey:
                gmwidg.infront()
                if gmwidg.gamemodel.players and gmwidg.gamemodel.isObservationGame():
                    gmwidg.light_on_off(False)
                    text = gmwidg.game_info_label.get_text()
                    gmwidg.game_info_label.set_markup(
                        '<span color="black" weight="bold">%s</span>' % text)

        self.key2cid[gmwidg.notebookKey] = headbook.connect_after("switch-page", callback, gmwidg)
        gmwidg.infront()

        align = gamewidget.createAlignment(0, 0, 0, 0)
        align.show()
        align.add(gmwidg.infobar)
        self.notebooks["messageArea"].append_page(align, None)
        self.notebooks["board"].append_page(gmwidg.boardvbox, None)
        gmwidg.boardvbox.show_all()
        for panel, instance in zip(self.sidePanels, gmwidg.panels):
            self.notebooks[panel.__name__].append_page(instance, None)
            instance.show_all()
        self.notebooks["buttons"].append_page(gmwidg.stat_hbox, None)
        gmwidg.stat_hbox.show_all()

        if headbook.get_n_pages() == 1:
            self.show_tabs(not conf.get("hideTabs", False))
        else:
            # We should always show tabs if more than one exists
            self.show_tabs(True)

        headbook.set_current_page(-1)

        widgets = gamewidget.getWidgets()
        if headbook.get_n_pages() == 1 and not widgets["show_sidepanels"].get_active():
            self.zoomToBoard(True)
コード例 #15
0
ファイル: __init__.py プロジェクト: teacoffee2017/pychess
class Database(GObject.GObject, Perspective):
    __gsignals__ = {
        'chessfile_opened0': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_opened': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
        'chessfile_closed': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'chessfile_imported': (GObject.SignalFlags.RUN_FIRST, None, (object, )),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "database", _("Database"))
        self.widgets = gamewidget.getWidgets()
        self.first_run = True
        self.chessfile = None
        self.chessfiles = []
        self.importer = None
        self.gamelists = []
        self.filter_panels = []
        self.opening_tree_panels = []
        self.preview_panels = []
        self.notebooks = {}
        self.page_dict = {}
        self.connect("chessfile_opened0", self.on_chessfile_opened0)
        self.dockLocation = addUserConfigPrefix("pydock-database.xml")

    @property
    def gamelist(self):
        if self.chessfile is None:
            return None
        else:
            return self.gamelists[self.chessfiles.index(self.chessfile)]

    @property
    def filter_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.filter_panels[self.chessfiles.index(self.chessfile)]

    @property
    def opening_tree_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.opening_tree_panels[self.chessfiles.index(self.chessfile)]

    @property
    def preview_panel(self):
        if self.chessfile is None:
            return None
        else:
            return self.preview_panels[self.chessfiles.index(self.chessfile)]

    def create_toolbuttons(self):
        self.import_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_CONVERT)
        self.import_button.set_tooltip_text(_("Import PGN file"))
        self.import_button.connect("clicked", self.on_import_clicked)

        self.save_as_button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_SAVE_AS)
        self.save_as_button.set_tooltip_text(_("Save to PGN file as..."))
        self.save_as_button.connect("clicked", self.on_save_as_clicked)

    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])

    def on_switch_page(self, notebook, page, page_num):
        if page in self.page_dict:
            self.chessfile = self.page_dict[page][0]
            i = self.chessfiles.index(self.chessfile)

            self.notebooks["gamelist"].set_current_page(i)
            self.notebooks["OpeningTreePanel"].set_current_page(i)
            self.notebooks["FilterPanel"].set_current_page(i)
            self.notebooks["PreviewPanel"].set_current_page(i)

    def set_sensitives(self, on):
        self.import_button.set_sensitive(on)
        self.widgets["import_chessfile"].set_sensitive(on)
        self.widgets["database_save_as"].set_sensitive(on)
        self.widgets["import_endgame_nl"].set_sensitive(on)
        self.widgets["import_twic"].set_sensitive(on)

    def open_chessfile(self, filename):
        if self.first_run:
            self.init_layout()
            self.first_run = False

        perspective_manager.activate_perspective("database")

        self.progress_dialog.set_title(_("Open"))
        self.progressbar0.hide()
        self.spinner.show()
        self.spinner.start()

        def opening():
            if filename.endswith(".pgn"):
                GLib.idle_add(self.progressbar1.show)
                GLib.idle_add(self.progressbar1.set_text, _("Opening chessfile..."))
                chessfile = PGNFile(protoopen(filename), self.progressbar1)
                self.importer = chessfile.init_tag_database()
                if self.importer is not None and self.importer.cancel:
                    chessfile.tag_database.close()
                    if os.path.isfile(chessfile.sqlite_path):
                        os.remove(chessfile.sqlite_path)
                    chessfile = None
                else:
                    chessfile.init_scoutfish()
                    chessfile.init_chess_db()
            elif filename.endswith(".epd"):
                self.importer = None
                chessfile = epd.load(protoopen(filename))
            elif filename.endswith(".olv"):
                self.importer = None
                chessfile = olv.load(protoopen(filename, encoding="utf-8"))
            elif filename.endswith(".fen"):
                self.importer = None
                chessfile = fen.load(protoopen(filename))
            else:
                self.importer = None
                chessfile = None

            GLib.idle_add(self.spinner.stop)
            GLib.idle_add(self.progress_dialog.hide)

            if chessfile is not None:
                self.chessfile = chessfile
                self.chessfiles.append(chessfile)
                GLib.idle_add(self.emit, "chessfile_opened0", chessfile)
            else:
                if self.chessfile is None:
                    self.close(None)

        thread = threading.Thread(target=opening)
        thread.daemon = True
        thread.start()

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            if self.importer is not None:
                self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_chessfile_opened0(self, persp, chessfile):
        page = Gtk.Alignment()
        tabcontent, close_button = self.get_tabcontent(chessfile)
        self.headbook.append_page(page, tabcontent)
        self.page_dict[page] = (chessfile, close_button)
        page.show_all()

        gamelist = GameList(self)
        self.gamelists.append(gamelist)
        opening_tree_panel = OpeningTreePanel(self)
        self.opening_tree_panels.append(opening_tree_panel)
        filter_panel = FilterPanel(self)
        self.filter_panels.append(filter_panel)
        preview_panel = PreviewPanel(self)
        self.preview_panels.append(preview_panel)

        self.notebooks["gamelist"].append_page(gamelist.box)
        self.notebooks["OpeningTreePanel"].append_page(opening_tree_panel.box)
        self.notebooks["FilterPanel"].append_page(filter_panel.box)
        self.notebooks["PreviewPanel"].append_page(preview_panel.box)

        self.headbook.set_current_page(self.headbook.get_n_pages() - 1)

        gamelist.load_games()
        opening_tree_panel.update_tree(load_games=False)

        self.set_sensitives(True)
        self.emit("chessfile_opened", chessfile)

    def close(self, close_button):
        for page in list(self.page_dict.keys()):
            if self.page_dict[page][1] == close_button:
                chessfile = self.page_dict[page][0]
                i = self.chessfiles.index(chessfile)
                self.notebooks["gamelist"].remove_page(i)
                self.notebooks["OpeningTreePanel"].remove_page(i)
                self.notebooks["FilterPanel"].remove_page(i)
                self.notebooks["PreviewPanel"].remove_page(i)
                del self.gamelists[i]
                del self.filter_panels[i]
                del self.chessfiles[i]
                chessfile.close()

                del self.page_dict[page]
                self.headbook.remove_page(self.headbook.page_num(page))
                break

        if len(self.chessfiles) == 0:
            self.set_sensitives(False)
            perspective_manager.disable_perspective("database")

        self.emit("chessfile_closed")

    def on_import_endgame_nl(self):
        self.do_import(JvR)

        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    def on_import_twic(self):
        LATEST = get_latest_twic()
        if LATEST is None:
            return

        html = "http://www.theweekinchess.com/html/twic%s.html"
        twic = []

        pgn = "https://raw.githubusercontent.com/rozim/ChessData/master/Twic/fix-twic%s.pgn"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(210, 920):
            twic.append((html % i, pgn % i))

        pgn = "http://www.theweekinchess.com/zips/twic%sg.zip"
        # pgn = "/home/tamas/PGN/twic/twic%sg.zip"
        for i in range(920, LATEST + 1):
            twic.append((html % i, pgn % i))

        twic.append((html % LATEST, pgn % LATEST))

        # import limited to latest twic .pgn for now
        twic = twic[-1:]

        self.do_import(twic)
        response = self.progress_dialog.run()
        if response == Gtk.ResponseType.CANCEL:
            self.importer.do_cancel()
        self.progress_dialog.hide()

    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

    def save_records(self, records, to_file):
        f = self.chessfile.handle
        for i, rec in enumerate(records):
            offs = rec["Offset"]

            f.seek(offs)
            game = ''
            for line in f:
                if line.startswith('[Event "'):
                    if game:
                        break  # Second one, start of next game
                    else:
                        game = line  # First occurence
                elif game:
                    game += line
            to_file.write(game)

    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()

    # @profile_me
    def importing(self, filenames):
        drop_indexes(self.chessfile.engine)

        self.importer = PgnImport(self.chessfile, append_pgn=True)
        self.importer.initialize()
        for i, filename in enumerate(filenames):
            GLib.idle_add(self.progressbar0.set_fraction, i / float(len(filenames)))
            # GLib.idle_add(self.progressbar0.set_text, filename)
            if self.importer.cancel:
                break
            if isinstance(filename, tuple):
                info_link, pgn_link = filename
                self.importer.do_import(pgn_link, info=info_link, progressbar=self.progressbar1)
            else:
                self.importer.do_import(filename, progressbar=self.progressbar1)

        GLib.idle_add(self.progressbar1.set_text, _("Recreating indexes..."))

        # .sqlite
        create_indexes(self.chessfile.engine)

        # .scout
        self.chessfile.init_scoutfish()

        # .bin
        self.chessfile.init_chess_db()

        self.chessfile.set_tag_filter(None)
        self.chessfile.set_fen_filter(None)
        self.chessfile.set_scout_filter(None)
        GLib.idle_add(self.gamelist.load_games)
        GLib.idle_add(self.emit, "chessfile_imported", self.chessfile)
        GLib.idle_add(self.progress_dialog.hide)

    def do_import(self, filenames):
        self.progress_dialog.set_title(_("Import"))
        self.spinner.hide()
        if len(filenames) == 1:
            self.progressbar0.hide()
        else:
            self.progressbar0.show()
        self.progressbar1.show()
        self.progressbar1.set_text(_("Preparing to start import..."))

        thread = threading.Thread(target=self.importing, args=(filenames, ))
        thread.daemon = True
        thread.start()

    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()

    def get_tabcontent(self, chessfile):
        tabcontent = createAlignment(0, 0, 0, 0)
        hbox = Gtk.HBox()
        hbox.set_spacing(4)
        hbox.pack_start(createImage(pgn_icon), False, True, 0)

        close_button = Gtk.Button()
        close_button.set_property("can-focus", False)
        close_button.add(createImage(gtk_close))
        close_button.set_relief(Gtk.ReliefStyle.NONE)
        close_button.set_size_request(20, 18)
        close_button.connect("clicked", self.close)
        hbox.pack_end(close_button, False, True, 0)

        name, ext = os.path.splitext(chessfile.path)
        basename = os.path.basename(name)
        info = "%s.%s" % (basename, ext[1:])
        tooltip = "%s\ncontaining %s games" % (chessfile.path, chessfile.count)
        tabcontent.set_tooltip_text(tooltip)

        label = Gtk.Label(info)
        hbox.pack_start(label, False, True, 0)

        tabcontent.add(hbox)
        tabcontent.show_all()
        return tabcontent, close_button
コード例 #16
0
ファイル: __init__.py プロジェクト: stevexyz/pychess
class FICS(GObject.GObject, Perspective):
    __gsignals__ = {
        'logout': (GObject.SignalFlags.RUN_FIRST, None, ()),
        'autoLogout': (GObject.SignalFlags.RUN_FIRST, None, ()),
    }

    def __init__(self):
        log.debug("FICS.__init__: starting")
        GObject.GObject.__init__(self)
        Perspective.__init__(self, "fics", _("ICS"))
        self.dockLocation = addUserConfigPrefix("pydock-fics.xml")
        self.first_run = True

    def create_toolbuttons(self):
        def on_logoff_clicked(button):
            self.emit("logout")
            self.close()

        self.logoff_button = Gtk.ToolButton.new_from_stock(
            Gtk.STOCK_DISCONNECT)
        self.logoff_button.set_tooltip_text(_("Log Off"))
        self.logoff_button.set_label("logoff")
        self.logoff_button.connect("clicked", on_logoff_clicked)

        def on_minute_1_clicked(button):
            self.connection.client.run_command("1-minute")

        def on_minute_3_clicked(button):
            self.connection.client.run_command("3-minute")

        def on_minute_5_clicked(button):
            self.connection.client.run_command("5-minute")

        def on_minute_15_clicked(button):
            self.connection.client.run_command("15-minute")

        def on_minute_25_clicked(button):
            self.connection.client.run_command("25-minute")

        def on_chess960_clicked(button):
            self.connection.client.run_command("chess960")

        self.minute_1_button = Gtk.ToggleToolButton()
        self.minute_1_button.set_label("1")
        self.minute_1_button.set_tooltip_text(
            _("New game from 1-minute playing pool"))
        self.minute_1_button.connect("clicked", on_minute_1_clicked)

        self.minute_3_button = Gtk.ToggleToolButton()
        self.minute_3_button.set_label("3")
        self.minute_3_button.set_tooltip_text(
            _("New game from 3-minute playing pool"))
        self.minute_3_button.connect("clicked", on_minute_3_clicked)

        self.minute_5_button = Gtk.ToggleToolButton()
        self.minute_5_button.set_label("5")
        self.minute_5_button.set_tooltip_text(
            _("New game from 5-minute playing pool"))
        self.minute_5_button.connect("clicked", on_minute_5_clicked)

        self.minute_15_button = Gtk.ToggleToolButton()
        self.minute_15_button.set_label("15")
        self.minute_15_button.set_tooltip_text(
            _("New game from 15-minute playing pool"))
        self.minute_15_button.connect("clicked", on_minute_15_clicked)

        self.minute_25_button = Gtk.ToggleToolButton()
        self.minute_25_button.set_label("25")
        self.minute_25_button.set_tooltip_text(
            _("New game from 25-minute playing pool"))
        self.minute_25_button.connect("clicked", on_minute_25_clicked)

        self.chess960_button = Gtk.ToggleToolButton()
        self.chess960_button.set_label("960")
        self.chess960_button.set_tooltip_text(
            _("New game from Chess960 playing pool"))
        self.chess960_button.connect("clicked", on_chess960_clicked)

    def init_layout(self):
        perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        perspective_manager.set_perspective_widget("fics", perspective_widget)
        perspective_manager.set_perspective_menuitems("fics", self.menuitems)

        self.infobar = InfoBarNotebook("fics_lounge_infobar")
        self.infobar.hide()
        perspective_widget.pack_start(self.infobar, False, False, 0)

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

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

        self.docks["ficshome"] = (Gtk.Label(label="ficshome"),
                                  self.notebooks["ficshome"], 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["ficshome"][1], CENTER,
                                  self.docks["ficshome"][0], "ficshome")
            leaf.setDockable(False)

            console_leaf = leaf.dock(self.docks["ConsolePanel"][1], SOUTH,
                                     self.docks["ConsolePanel"][0],
                                     "ConsolePanel")
            console_leaf.dock(self.docks["NewsPanel"][1], CENTER,
                              self.docks["NewsPanel"][0], "NewsPanel")

            seek_leaf = leaf.dock(self.docks["SeekListPanel"][1], WEST,
                                  self.docks["SeekListPanel"][0],
                                  "SeekListPanel")
            seek_leaf.dock(self.docks["SeekGraphPanel"][1], CENTER,
                           self.docks["SeekGraphPanel"][0], "SeekGraphPanel")
            seek_leaf.dock(self.docks["PlayerListPanel"][1], CENTER,
                           self.docks["PlayerListPanel"][0], "PlayerListPanel")
            seek_leaf.dock(self.docks["GameListPanel"][1], CENTER,
                           self.docks["GameListPanel"][0], "GameListPanel")
            seek_leaf.dock(self.docks["ArchiveListPanel"][1], CENTER,
                           self.docks["ArchiveListPanel"][0],
                           "ArchiveListPanel")

            leaf = leaf.dock(self.docks["ChatPanel"][1], SOUTH,
                             self.docks["ChatPanel"][0], "ChatPanel")
            # leaf.dock(self.docks["LecturesPanel"][1], CENTER, self.docks["LecturesPanel"][0], "LecturesPanel")

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

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

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

        log.debug("FICS.__init__: finished")

    def open_lounge(self, connection, helperconn, host):
        if self.first_run:
            self.init_layout()

        self.connection = connection
        self.helperconn = helperconn
        self.host = host

        self.finger_sent = False
        self.messages = []
        self.players = []
        self.game_cids = {}

        self.widgets = uistuff.GladeWidgets("fics_lounge.glade")
        self.widgets["fics_lounge"].hide()

        fics_home = self.widgets["fics_home"]
        self.widgets["fics_lounge_content_hbox"].remove(fics_home)

        self.archive_list = self.widgets["archiveListContent"]
        self.widgets["fics_panels_notebook"].remove(self.archive_list)

        self.games_list = self.widgets["gamesListContent"]
        self.widgets["fics_panels_notebook"].remove(self.games_list)

        self.news_list = self.widgets["news"]
        self.widgets["fics_home"].remove(self.news_list)

        self.players_list = self.widgets["playersListContent"]
        self.widgets["fics_panels_notebook"].remove(self.players_list)

        self.seek_graph = self.widgets["seekGraphContent"]
        self.widgets["fics_panels_notebook"].remove(self.seek_graph)

        self.seek_list = self.widgets["seekListContent"]
        self.widgets["fics_panels_notebook"].remove(self.seek_list)

        self.seek_challenge = SeekChallengeSection(self)

        def on_autoLogout(alm):
            self.emit("autoLogout")
            self.close()

        self.connection.alm.connect("logOut", on_autoLogout)
        self.connection.connect("disconnected",
                                lambda connection: self.close())
        self.connection.connect("error", self.on_connection_error)
        if self.connection.isRegistred():
            numtimes = conf.get("numberOfTimesLoggedInAsRegisteredUser", 0) + 1
            conf.set("numberOfTimesLoggedInAsRegisteredUser", numtimes)
        self.connection.em.connect(
            "onCommandNotFound", lambda em, cmd: log.error(
                "Fics answered '%s': Command not found" % cmd))
        self.connection.bm.connect("playGameCreated", self.onPlayGameCreated)
        self.connection.bm.connect("obsGameCreated", self.onObserveGameCreated)
        self.connection.bm.connect("exGameCreated", self.onObserveGameCreated)
        self.connection.fm.connect("fingeringFinished", self.onFinger)
        # the rest of these relay server messages to the lounge infobar
        self.connection.bm.connect("tooManySeeks", self.tooManySeeks)
        self.connection.bm.connect("nonoWhileExamine", self.nonoWhileExamine)
        self.connection.bm.connect("matchDeclined", self.matchDeclined)
        self.connection.bm.connect("player_on_censor", self.player_on_censor)
        self.connection.bm.connect("player_on_noplay", self.player_on_noplay)
        self.connection.bm.connect("req_not_fit_formula",
                                   self.req_not_fit_formula)
        self.connection.glm.connect("seek-updated", self.on_seek_updated)
        self.connection.glm.connect("our-seeks-removed",
                                    self.our_seeks_removed)
        self.connection.cm.connect("arrivalNotification",
                                   self.onArrivalNotification)
        self.connection.cm.connect("departedNotification",
                                   self.onDepartedNotification)

        def get_top_games():
            if perspective_manager.current_perspective == self:
                self.connection.client.run_command("games *19")
            return True

        if self.connection.ICC:
            self.event_id = GLib.timeout_add_seconds(5, get_top_games)

        for user in self.connection.notify_users:
            user = self.connection.players.get(user)
            self.user_from_notify_list_is_present(user)

        self.userinfo = UserInfoSection(self.widgets, self.connection,
                                        self.host, self)
        if not self.first_run:
            self.notebooks["ficshome"].remove_page(-1)
        self.notebooks["ficshome"].append_page(fics_home)

        self.panels = [
            panel.Sidepanel().load(self.widgets, self.connection, self)
            for panel in self.sidePanels
        ]

        for panel, instance in zip(self.sidePanels, self.panels):
            if not self.first_run:
                self.notebooks[panel.__name__].remove_page(-1)
            self.notebooks[panel.__name__].append_page(instance)
            instance.show()

        tool_buttons = [
            self.logoff_button,
        ]
        self.quick_seek_buttons = []
        if self.connection.ICC:
            self.quick_seek_buttons = [
                self.minute_1_button, self.minute_3_button,
                self.minute_5_button, self.minute_15_button,
                self.minute_25_button, self.chess960_button
            ]
            tool_buttons += self.quick_seek_buttons
        perspective_manager.set_perspective_toolbuttons("fics", tool_buttons)

        if self.first_run:
            self.first_run = False

        # After all panel is set up we can push initial messages out
        self.connection.com.onConsoleMessage("", self.connection.ini_messages)

    def show(self):
        perspective_manager.activate_perspective("fics")

    def present(self):
        perspective_manager.activate_perspective("fics")

    def on_connection_error(self, connection, error):
        log.warning("FICS.on_connection_error: %s" % repr(error))
        self.close()

    def close(self):
        try:
            self.widgets = None
        except TypeError:
            pass
        except AttributeError:
            pass
        perspective_manager.disable_perspective("fics")

    def onPlayGameCreated(self, bm, ficsgame):
        log.debug("FICS.onPlayGameCreated: %s" % ficsgame)

        for message in self.messages:
            message.dismiss()
        del self.messages[:]

        if self.connection.ICC:
            for button in self.quick_seek_buttons:
                button.set_active(False)

        timemodel = TimeModel(ficsgame.minutes * 60, ficsgame.inc)

        gamemodel = ICGameModel(self.connection, ficsgame, timemodel)
        gamemodel.connect("game_started", self.onGameModelStarted, ficsgame)

        wplayer, bplayer = ficsgame.wplayer, ficsgame.bplayer

        # We start
        if wplayer.name.lower() == self.connection.getUsername().lower():
            player0tup = (LOCAL, Human, (WHITE, wplayer.long_name(),
                                         wplayer.name,
                                         wplayer.getRatingForCurrentGame()),
                          wplayer.long_name())
            player1tup = (REMOTE, ICPlayer,
                          (gamemodel, bplayer.name, ficsgame.gameno, BLACK,
                           bplayer.long_name(),
                           bplayer.getRatingForCurrentGame()),
                          bplayer.long_name())

        # She starts
        else:
            player1tup = (LOCAL, Human, (BLACK, bplayer.long_name(),
                                         bplayer.name,
                                         bplayer.getRatingForCurrentGame()),
                          bplayer.long_name())
            player0tup = (REMOTE, ICPlayer,
                          (gamemodel, wplayer.name, ficsgame.gameno, WHITE,
                           wplayer.long_name(),
                           wplayer.getRatingForCurrentGame()),
                          wplayer.long_name())

        perspective = perspective_manager.get_perspective("games")
        if not ficsgame.board.fen:
            asyncio. async (perspective.generalStart(gamemodel, player0tup,
                                                     player1tup))
        else:
            asyncio. async (perspective.generalStart(
                gamemodel, player0tup, player1tup,
                (StringIO(ficsgame.board.fen), fen, 0, -1)))

    def onGameModelStarted(self, gamemodel, ficsgame):
        self.connection.bm.onGameModelStarted(ficsgame.gameno)

    def onObserveGameCreated(self, bm, ficsgame):
        log.debug("FICS.onObserveGameCreated: %s" % ficsgame)

        timemodel = TimeModel(ficsgame.minutes * 60, ficsgame.inc)

        gamemodel = ICGameModel(self.connection, ficsgame, timemodel)
        gamemodel.connect("game_started", self.onGameModelStarted, ficsgame)

        # The players need to start listening for moves IN this method if they
        # want to be noticed of all moves the FICS server sends us from now on
        wplayer, bplayer = ficsgame.wplayer, ficsgame.bplayer

        player0tup = (REMOTE, ICPlayer,
                      (gamemodel, wplayer.name, ficsgame.gameno, WHITE,
                       wplayer.long_name(), wplayer.getRatingForCurrentGame()),
                      wplayer.long_name())
        player1tup = (REMOTE, ICPlayer,
                      (gamemodel, bplayer.name, ficsgame.gameno, BLACK,
                       bplayer.long_name(), bplayer.getRatingForCurrentGame()),
                      bplayer.long_name())

        perspective = perspective_manager.get_perspective("games")
        asyncio. async (perspective.generalStart(
            gamemodel, player0tup, player1tup,
            (StringIO(ficsgame.board.pgn), pgn, 0, -1)))

        if ficsgame.relation == IC_POS_OBSERVING_EXAMINATION:
            if 1:  # int(self.connection.lvm.variablesBackup["kibitz"]) == 0:
                self.connection.cm.whisper(
                    _("You have to set kibitz on to see bot messages here."))
            self.connection.fm.finger(bplayer.name)
            self.connection.fm.finger(wplayer.name)
        elif ficsgame.relation == IC_POS_EXAMINATING:
            gamemodel.examined = True
        if not self.connection.ICC:
            allob = 'allob ' + str(ficsgame.gameno)
            gamemodel.connection.client.run_command(allob)

    def onFinger(self, fm, finger):
        titles = finger.getTitles()
        if titles is not None:
            name = finger.getName()
            player = self.connection.players.get(name)
            for title in titles:
                player.titles.add(TITLES[title])

    def tooManySeeks(self, bm):
        label = Gtk.Label(label=_(
            "You may only have 3 outstanding seeks at the same time. If you want \
            to add a new seek you must clear your currently active seeks. Clear your seeks?"
        ))
        label.set_width_chars(80)
        label.props.xalign = 0
        label.set_line_wrap(True)

        def response_cb(infobar, response, message):
            if response == Gtk.ResponseType.YES:
                self.connection.client.run_command("unseek")
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.QUESTION, label, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_YES, Gtk.ResponseType.YES))
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_NO, Gtk.ResponseType.NO))
        self.messages.append(message)
        self.infobar.push_message(message)

    def nonoWhileExamine(self, bm):
        label = Gtk.Label(_("You can't touch this! You are examining a game."))

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, label, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def matchDeclined(self, bm, player):
        text = _(" has declined your offer for a match")
        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def player_on_censor(self, bm, player):
        text = _(" is censoring you")
        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def player_on_noplay(self, bm, player):
        text = _(" noplay listing you")
        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def req_not_fit_formula(self, bm, player, formula):
        content = get_infobarmessage_content2(
            player, _(" uses a formula not fitting your match request:"),
            formula)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, content, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def on_seek_updated(self, glm, message_text):
        if "manual accept" in message_text:
            message_text.replace("to manual accept", _("to manual accept"))
        elif "automatic accept" in message_text:
            message_text.replace("to automatic accept",
                                 _("to automatic accept"))
        if "rating range now" in message_text:
            message_text.replace("rating range now", _("rating range now"))
        label = Gtk.Label(label=_("Seek updated") + ": " + message_text)

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, label, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def our_seeks_removed(self, glm):
        label = Gtk.Label(label=_("Your seeks have been removed"))

        def response_cb(infobar, response, message):
            message.dismiss()
            return False

        message = InfoBarMessage(Gtk.MessageType.INFO, label, response_cb)
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def _connect_to_player_changes(self, player):
        player.connect("ratings_changed", self._replace_notification_message,
                       player)
        player.connect("notify::titles", self._replace_notification_message,
                       None, player)

    def onArrivalNotification(self, cm, player):
        log.debug("%s" % player,
                  extra={
                      "task":
                      (self.connection.username, "onArrivalNotification")
                  })
        self._add_notification_message(player,
                                       _(" has arrived"),
                                       chat=True,
                                       replace=True)
        if player not in self.players:
            self.players.append(player)
            self._connect_to_player_changes(player)

    def onDepartedNotification(self, cm, player):
        self._add_notification_message(player,
                                       _(" has departed"),
                                       replace=True)

    def user_from_notify_list_is_present(self, player):
        self._add_notification_message(player,
                                       _(" is present"),
                                       chat=True,
                                       replace=True)
        if player not in self.players:
            self.players.append(player)
            self._connect_to_player_changes(player)

    def _add_notification_message(self,
                                  player,
                                  text,
                                  chat=False,
                                  replace=False):
        if replace:
            for message in self.messages:
                if isinstance(message, PlayerNotificationMessage
                              ) and message.player == player:
                    message.dismiss()

        content = get_infobarmessage_content(player, text)

        def response_cb(infobar, response, message):
            if response == 1:
                if player is None:
                    return
                self.chat.openChatWithPlayer(player.name)
            if response == 2:
                if player is None:
                    return
                self.connection.client.run_command("follow %s" % player.name)
            message.dismiss()
            #             self.messages.remove(message)
            return False

        message = PlayerNotificationMessage(Gtk.MessageType.INFO, content,
                                            response_cb, player, text)
        if chat:
            message.add_button(InfoBarMessageButton(_("Chat"), 1))
            message.add_button(InfoBarMessageButton(_("Follow"), 2))
        message.add_button(
            InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL))
        self.messages.append(message)
        self.infobar.push_message(message)

    def _replace_notification_message(self, obj, prop, rating_type, player):
        log.debug("%s %s" % (repr(obj), player),
                  extra={
                      "task": (self.connection.username,
                               "_replace_notification_message")
                  })
        for message in self.messages:
            if isinstance(message, PlayerNotificationMessage) and \
                    message.player == player:
                message.update_content(
                    get_infobarmessage_content(player, message.text))
        return False
コード例 #17
0
ファイル: ChatWindow.py プロジェクト: ME7ROPOLIS/pychess
class ChatWindow(object):
    def __init__(self, widgets, connection):
        self.connection = connection
        self.window = None

        widgets["show_chat_button"].connect("clicked", self.showChat)
        connection.cm.connect("privateMessage", self.onPersonMessage)
        connection.connect("disconnected", self.onDisconnected)

        self.viewspanel = ViewsPanel(self.connection)
        self.channelspanel = ChannelsPanel(self.connection)
        self.infopanel = InfoPanel(self.connection)
        self.panels = [self.viewspanel, self.channelspanel, self.infopanel]
        self.viewspanel.connect('channel_content_Changed',
                                self.channelspanel.channel_Highlight, id)

    @idle_add
    def onDisconnected(self, conn):
        if self.window:
            self.window.hide()

    def showChat(self, *widget):
        if not self.window:
            self.initUi()
        self.window.show_all()
        self.window.present()

    def initUi(self):
        self.window = Gtk.Window()
        self.window.set_border_width(12)
        self.window.set_icon_name("pychess")
        self.window.set_title("PyChess - Internet Chess Chat")
        self.window.connect_after("delete-event",
                                  lambda w, e: w.hide() or True)

        uistuff.keepWindowSize("chat", self.window, defaultSize=(650, 400))

        self.dock = PyDockTop("icchat")
        self.dock.show()
        self.window.add(self.dock)

        leaf = self.dock.dock(self.viewspanel,
                         CENTER,
                         Gtk.Label(label="chat"),
                         "chat")
        leaf.setDockable(False)

        self.channelspanel.connect('conversationAdded',
                                   self.onConversationAdded)
        self.channelspanel.connect('conversationRemoved',
                                   self.onConversationRemoved)
        self.channelspanel.connect('conversationSelected',
                                   self.onConversationSelected)
        leaf.dock(self.channelspanel,
                  WEST,
                  Gtk.Label(label=_("Conversations")),
                  "conversations")

        leaf.dock(self.infopanel,
                  EAST,
                  Gtk.Label(label=_("Conversation info")),
                  "info")

        for panel in self.panels:
            panel.show_all()
            panel.start()

    def onConversationAdded(self, panel, grp_id, text, grp_type):
        chatView = ChatView()
        plus_channel = '+channel ' + str(grp_id)
        self.connection.cm.connection.client.run_command(plus_channel)
        for panel in self.panels:
            panel.addItem(grp_id, text, grp_type, chatView)

    def onConversationRemoved(self, panel, grp_id):
        minus_channel = '-channel ' + str(grp_id)
        self.connection.cm.connection.client.run_command(minus_channel)
        for panel in self.panels:
            panel.removeItem(grp_id)

    def onConversationSelected(self, panel, grp_id):
        for panel in self.panels:
            panel.selectItem(grp_id)

    @idle_add
    def onPersonMessage(self, cm, name, title, isadmin, text):
        console_active = False
        for window in Gtk.Window.list_toplevels():
            if window.is_active():
                window_icon_name = window.get_icon_name()
                if window_icon_name is not None and "pychess" in window_icon_name:
                    console_active = True
                    break

        if self.connection.bm.isPlaying() or console_active:
            if not self.window:
                self.initUi()
        else:
            self.showChat()
            self.window.set_urgency_hint(True)
            self.initial_focus_id = self.window.connect(
                "focus-in-event", self.on_initial_focus_in)

    def on_initial_focus_in(self, widget, event):
        self.window.set_urgency_hint(False)
        self.window.disconnect(self.initial_focus_id)
        return False

    def openChatWithPlayer(self, name):
        self.showChat()
        self.window.get_window().raise_()
        cm = self.connection.cm
        self.onPersonMessage(cm, name, "", False, "")
        self.channelspanel.onPersonMessage(cm, name, "", False, "")