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)
def init_tag_database(self): sqlite_path = os.path.splitext(self.path)[0] + '.sqlite' self.engine = dbmodel.get_engine(sqlite_path) self.tag_database = TagDatabase(self.engine) # Import .pgn header tags to .sqlite database size = self.size if size > 0 and self.tag_database.count == 0: if size > 10000000: drop_indexes(self.engine) importer = PgnImport(self) importer.do_import(self.path, progressbar=self.progressbar) if size > 10000000: create_indexes(self.engine)
def row_activated(self, widget, path, col): if path is None: return filename = addDataPrefix("lectures/%s" % LESSONS[path[0]][0]) chessfile = PGNFile(protoopen(filename)) self.importer = PgnImport(chessfile) chessfile.init_tag_database(self.importer) records, plys = chessfile.get_records() rec = records[random.randrange(0, len(records))] print(rec) timemodel = TimeModel(0, 0) gamemodel = GameModel(timemodel) gamemodel.set_lesson_game() chessfile.loadToModel(rec, -1, gamemodel) name = conf.get("firstName", _("You")) p0 = (LOCAL, Human, (WHITE, name), name) name = "pychessbot" p1 = (LOCAL, Human, (BLACK, name), name) gamemodel.status = WAITING_TO_START perspective = perspective_manager.get_perspective("games") asyncio. async (perspective.generalStart(gamemodel, p0, p1))
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 init_tag_database(self): """ Create/open .sqlite database of game header tags """ sqlite_path = os.path.splitext(self.path)[0] + '.sqlite' self.engine = dbmodel.get_engine(sqlite_path) self.tag_database = TagDatabase(self.engine) # Import .pgn header tags to .sqlite database size = self.size if size > 0 and self.tag_database.count == 0: if size > 10000000: drop_indexes(self.engine) importer = PgnImport(self) importer.do_import(self.path, progressbar=self.progressbar) if size > 10000000: create_indexes(self.engine)
def init_tag_database(self, importer=None): """ Create/open .sqlite database of game header tags """ # Import .pgn header tags to .sqlite database sqlite_path = self.path.replace(".pgn", ".sqlite") if os.path.isfile( self.path) and os.path.isfile(sqlite_path) and getmtime( self.path) > getmtime(sqlite_path): metadata.drop_all(self.engine) metadata.create_all(self.engine) ini_schema_version(self.engine) size = self.size if size > 0 and self.tag_database.count == 0: if size > 10000000: drop_indexes(self.engine) if self.progressbar is not None: from gi.repository import GLib GLib.idle_add(self.progressbar.set_text, _("Importing game headers...")) if importer is None: importer = PgnImport(self) importer.initialize() importer.do_import(self.path, progressbar=self.progressbar) if size > 10000000 and not importer.cancel: create_indexes(self.engine) return importer
def importing(): drop_indexes(self.gamelist.chessfile.engine) self.importer = PgnImport(self.gamelist.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: filename = unicode(filename) self.importer.do_import(filename, progressbar=self.progressbar1) GLib.idle_add(self.progressbar1.set_text, "Recreating indexes...") # .sqlite create_indexes(self.gamelist.chessfile.engine) # .scout self.gamelist.chessfile.init_scoutfish() if self.gamelist.chessfile.scoutfish is not None: self.gamelist.chessfile.scoutfish.make() # .bin self.gamelist.chessfile.init_chess_db() if self.gamelist.chessfile.chess_db is not None: self.gamelist.chessfile.chess_db.make() self.gamelist.chessfile.set_tags_filter("") self.gamelist.chessfile.set_fen_filter(FEN_START) self.gamelist.chessfile.set_scout_filter("") GLib.idle_add(self.gamelist.load_games) GLib.idle_add(self.emit, "chessfile_imported", self.gamelist.chessfile) GLib.idle_add(self.progress_dialog.hide)
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 init_tag_database(self, importer=None): """ Create/open .sqlite database of game header tags """ # Import .pgn header tags to .sqlite database sqlite_path = self.path.replace(".pgn", ".sqlite") if os.path.isfile(self.path) and os.path.isfile(sqlite_path) and getmtime(self.path) > getmtime(sqlite_path): metadata.drop_all(self.engine) metadata.create_all(self.engine) ini_schema_version(self.engine) size = self.size if size > 0 and self.tag_database.count == 0: if size > 10000000: drop_indexes(self.engine) if self.progressbar is not None: GLib.idle_add(self.progressbar.set_text, _("Importing game headers...")) if importer is None: importer = PgnImport(self) importer.initialize() importer.do_import(self.path, progressbar=self.progressbar) if size > 10000000 and not importer.cancel: create_indexes(self.engine) return importer
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)
def feed(pgnfile, lang): cf = load(protoopen(pgnfile)) cf.limit = 5000 importer = PgnImport(cf) cf.init_tag_database(importer) records, plys = cf.get_records() rows = [] old_eco = "" for rec in records: model = cf.loadToModel(rec) eco = rec["ECO"] opening = rec["White"] if opening is None: opening = "" variation = rec["Black"] if variation is None: variation = "" base = int(old_eco != eco) ply = len(model.moves) if ply == 0: cu = conn.cursor() cu.execute( "select * from openings where eco=? and lang='en' and base=1", (eco, )) res = cu.fetchone() if res is not None: hash = res[0] else: hash = memoryview(hash_struct.pack( model.boards[-1].board.hash)) if opening: rows.append((hash, base, eco, lang, opening, variation)) old_eco = eco c.executemany( "insert into openings(hash, base, eco, lang, opening, variation) values (?, ?, ?, ?, ?, ?)", rows) conn.commit()
def start_puzzle_from(filename): chessfile = PGNFile(protoopen(addDataPrefix("lectures/%s" % filename))) chessfile.limit = 1000 importer = PgnImport(chessfile) chessfile.init_tag_database(importer) records, plys = chessfile.get_records() rec = records[random.randrange(0, len(records))] timemodel = TimeModel(0, 0) gamemodel = GameModel(timemodel) gamemodel.set_practice_game() gamemodel.practice = ("puzzle", filename) chessfile.loadToModel(rec, 0, gamemodel) # TODO: change colors according to FEN! name = rec["White"] p0 = (LOCAL, Human, (WHITE, name), name) engine = discoverer.getEngineByName(stockfish_name) name = rec["Black"] ponder_off = True p1 = (ARTIFICIAL, discoverer.initPlayerEngine, (engine, BLACK, 20, variants[NORMALCHESS], 60, 0, 0, ponder_off), name) def fix_name(gamemodel, name): asyncio. async (gamemodel.start_analyzer(HINT, force_engine=stockfish_name)) gamemodel.players[1].name = name gamemodel.emit("players_changed") gamemodel.connect("game_started", fix_name, name) gamemodel.variant.need_initial_board = True gamemodel.status = WAITING_TO_START perspective = perspective_manager.get_perspective("games") asyncio. async (perspective.generalStart(gamemodel, p0, p1))
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_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, )), '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
text = text.splitlines() text = " ".join(text) text = text.replace('. ', '. ').replace('. ', '. ') text = text.replace(' )', ')').replace(' )', ')') text = text.replace('( ', '(').replace('( ', '(') text = text.replace(' }', '}').replace(' }', '}') text = text.replace('{ ', '{').replace('{ ', '{') return text filenames = ("atomic", "chess960rwch", "world_matches", "zh") for filename in filenames: print("Creating test methods for %s" % filename) pgnfile = load(protoopen('gamefiles/%s.pgn' % filename)) pgnfile.limit = 1000 importer = PgnImport(pgnfile) pgnfile.init_tag_database(importer) games, plys = pgnfile.get_records() for i, game in enumerate(games): print("%s/%s" % (i + 1, pgnfile.get_count())) orig = normalize(pgnfile.get_movetext(game)) model = pgnfile.loadToModel(game) new = [] walk(model.boards[0].board, new, model) new = normalize(" ".join(new)) # create test method test_method = create_test(orig, new)
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()
def importing(): self.importer = FIDEPlayersImport(self.gamelist.chessfile.engine) self.importer.import_players(progressbar=self.progressbar) GLib.idle_add(self.progress_dialog.hide)
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()