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