def __init__(self, *args, is_offline, **kwargs): super().__init__(*args, **kwargs) self.is_offline = is_offline self.online_languages = tesseract_download.get_downloadable_languages() # Translators: label of a list control containing bookmarks wx.StaticText(self, -1, _("Tesseract Languages")) listPanel = sc.SizedPanel(self) listPanel.SetSizerType("horizontal") listPanel.SetSizerProps(expand=True, align="center") self.tesseractLanguageList = ImmutableObjectListView( listPanel, wx.ID_ANY, style=wx.LC_REPORT | wx.SUNKEN_BORDER, size=(500, -1)) self.btnPanel = btnPanel = sc.SizedPanel(self, -1) btnPanel.SetSizerType("horizontal") btnPanel.SetSizerProps(expand=True) if not self.is_offline: # Translators: text of a button to add a language to Tesseract OCR Engine (best quality model) self.addBestButton = wx.Button(btnPanel, wx.ID_ANY, _("Download &Best Model")) # Translators: text of a button to add a language to Tesseract OCR Engine (fastest model) self.addFastButton = wx.Button(btnPanel, wx.ID_ANY, _("Download &Fast Model")) self.Bind(wx.EVT_BUTTON, self.onAdd, self.addFastButton) self.Bind(wx.EVT_BUTTON, self.onAdd, self.addBestButton) else: # Translators: text of a button to remove a language from Tesseract OCR Engine self.removeButton = wx.Button(btnPanel, wx.ID_REMOVE, _("&Remove")) self.Bind(wx.EVT_BUTTON, self.onRemove, id=wx.ID_REMOVE) self.tesseractLanguageList.Bind(wx.EVT_SET_FOCUS, self.onListFocus, self.tesseractLanguageList)
class SearchResultsPage(sc.SizedPanel): def __init__(self, parent, search_results, list_label): super().__init__(parent, -1) column_spec = ( ColumnDefn(_("Snippet"), "left", 255, operator.attrgetter("snippet")), ColumnDefn( _("Title"), "center", 255, operator.attrgetter("document_title") ), ColumnDefn(_("Page"), "right", 120, lambda ins: ins.page_index + 1), ) wx.StaticText(self, -1, list_label) self.result_list = ImmutableObjectListView(self, -1, columns=column_spec) self.result_list.set_objects(search_results, set_focus=False) self.result_list.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.onItemActivated, self.result_list ) def onItemActivated(self, event): selected_result = self.result_list.get_selected() page = selected_result.page_index position = Page.get_text_start_position( selected_result.page_id, selected_result.snippet ) uri = selected_result.document.uri.create_copy( openner_args=dict(page=page, position=position) ) # Translators: spoken message speech.announce("Openning document...") sounds.navigation.play() EBookReader.open_document_in_a_new_instance(uri)
def addControls(self, parent): # Translators: header of a group of controls in a dialog to view user's comments/highlights filterBox = make_sized_static_box(parent, _("Filter By")) self.filterPanel = AnnotationFilterPanel( filterBox, -1, annotator=self.annotator, filter_callback=self.onFilter, filter_by_book=not self.reader.ready, ) # Translators: header of a group of controls in a dialog to view user's comments/highlights sortBox = make_sized_static_box(parent, _("Sort By")) sortPanel = sc.SizedPanel(sortBox, -1) sortPanel.SetSizerType("horizontal") sortPanel.SetSizerProps(expand=True) sort_options = [ # Translators: text of a toggle button to sort comments/highlights list (_("Date"), AnnotationSortCriteria.Date), # Translators: text of a toggle button to sort comments/highlights list (_("Page"), AnnotationSortCriteria.Page), ] if not self.reader.ready: # Translators: text of a toggle button to sort comments/highlights list sort_options.append((_("Book"), AnnotationSortCriteria.Book)) for bt_label, srt_criteria in sort_options: tglButton = wx.ToggleButton(sortPanel, -1, bt_label) self._sort_toggles[tglButton] = srt_criteria self.Bind(wx.EVT_TOGGLEBUTTON, self.onSortToggle, tglButton) # Translators: text of a toggle button to sort comments/highlights list self.sortMethodToggle = wx.ToggleButton(sortPanel, -1, _("Ascending")) wx.StaticText(parent, -1, self.Title) self.itemsView = ImmutableObjectListView( parent, id=wx.ID_ANY, style=wx.LC_REPORT | wx.SUNKEN_BORDER ) self.itemsView.SetSizerProps(expand=True) self.buttonPanel = sc.SizedPanel(parent, -1) self.buttonPanel.SetSizerType("horizontal") # Translators: text of a button in a dialog to view comments/highlights wx.Button(self.buttonPanel, wx.ID_PREVIEW, _("&View...")) if self.can_edit: # Translators: text of a button in a dialog to view comments/highlights wx.Button(self.buttonPanel, wx.ID_EDIT, _("&Edit...")) self.Bind(wx.EVT_BUTTON, self.onEdit, id=wx.ID_EDIT) # Translators: text of a button in a dialog to view comments/highlights wx.Button(self.buttonPanel, wx.ID_DELETE, _("&Delete...")) # Translators: text of a button in a dialog to view comments/highlights exportButton = wx.Button(self.buttonPanel, -1, _("E&xport...")) self.Bind(wx.EVT_TOGGLEBUTTON, self.onSortMethodToggle, self.sortMethodToggle) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.onItemClick, self.itemsView) self.Bind(wx.EVT_LIST_KEY_DOWN, self.onKeyDown, self.itemsView) self.Bind(wx.EVT_BUTTON, self.onView, id=wx.ID_PREVIEW) self.Bind(wx.EVT_BUTTON, self.onDelete, id=wx.ID_DELETE) self.Bind(wx.EVT_BUTTON, self.onExport, exportButton) self.on_filter_and_sort_state_changed() self.set_items()
def addControls(self, parent): parent.SetSizerType("vertical") column_spec = ( # Translators: title of a list control colum ColumnDefn(_("Error"), "left", 255, operator.itemgetter(0)), # Translators: title of a list control colum ColumnDefn(_("File Name"), "center", 255, operator.itemgetter(1)), # Translators: title of a list control colum ColumnDefn(_("Title"), "right", 255, operator.itemgetter(2)), ) # Translators: label of a list control showing file copy errors wx.StaticText(parent, -1, _("Errors")) result_list = ImmutableObjectListView(parent, -1, columns=column_spec) reason = _("Failed to copy document") result_list.set_objects([(reason, *i) for i in self.info], set_focus=True)
def __init__(self, parent, search_results, list_label): super().__init__(parent, -1) column_spec = ( ColumnDefn(_("Snippet"), "left", 255, operator.attrgetter("snippet")), ColumnDefn( _("Title"), "center", 255, operator.attrgetter("document_title") ), ColumnDefn(_("Page"), "right", 120, lambda ins: ins.page_index + 1), ) wx.StaticText(self, -1, list_label) self.result_list = ImmutableObjectListView(self, -1, columns=column_spec) self.result_list.set_objects(search_results, set_focus=False) self.result_list.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.onItemActivated, self.result_list )
def addControls(self, parent): # Translators: label of a list control containing bookmarks wx.StaticText(parent, -1, _("Saved Bookmarks")) self.annotationsListCtrl = ImmutableObjectListView(parent, wx.ID_ANY) # Translators: text of a button to remove bookmarks wx.Button(parent, wx.ID_DELETE, _("&Remove")) self.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.onItemClick, self.annotationsListCtrl ) self.Bind(wx.EVT_LIST_KEY_DOWN, self.onKeyDown, self.annotationsListCtrl) self.Bind( wx.EVT_LIST_END_LABEL_EDIT, self.onEndLabelEdit, self.annotationsListCtrl ) self.Bind(wx.EVT_BUTTON, self.onDelete, id=wx.ID_DELETE) wx.FindWindowById(wx.ID_DELETE).Enable(False) self._populate_list()
def addControls(self, parent): self.elementTypeRadio = EnumRadioBox( parent, -1, label=("Element Type"), choice_enum=ElementKind, majorDimension=0, style=wx.RA_SPECIFY_COLS, ) self.elementListViewLabel = wx.StaticText(parent, -1, _("Elements")) self.elementListView = ImmutableObjectListView( parent, wx.ID_ANY, columns=[ ColumnDefn(_("Name"), "left", 255, "name"), ], ) self.Bind(wx.EVT_RADIOBOX, self.onElementTypeRadioSelected, self.elementTypeRadio) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.onListItemActivated, self.elementListView) self.ElementInfo = namedtuple("ElementInfo", "type name text_range") self.__element_Info_cache = {} self.populate_element_list(self.elementTypeRadio.GetSelectedValue()) self.set_listview_label()
class AnnotationWithContentDialog(SimpleDialog): """View, edit, and manage notes and quotes.""" @classmethod def column_defn(cls): return ( # Translators: the title of a column in the comments/highlights list ColumnDefn("Excerpt", "left", 250, lambda a: a.content[:20]), # Translators: the title of a column in the comments/highlights list ColumnDefn("Section", "left", 200, "section_title"), # Translators: the title of a column in the comments/highlights list ColumnDefn("Page", "center", 150, lambda anot: anot.page_number + 1), # Translators: the title of a column in the comments/highlights list ColumnDefn( "Added", "right", 200, lambda a: format_datetime(a.date_created) ), ) def __init__(self, reader, annotator_cls, *args, can_edit=False, **kwargs): self.reader = reader self.annotator_cls = annotator_cls self.annotator = self.annotator_cls(reader) self.can_edit = can_edit self.service = wx.GetApp().service_handler.get_service("annotation") self._filter_and_sort_state = FilterAndSortState.create_default(self.annotator) self._sort_toggles = {} super().__init__(*args, **kwargs) def addControls(self, parent): # Translators: header of a group of controls in a dialog to view user's comments/highlights filterBox = make_sized_static_box(parent, _("Filter By")) self.filterPanel = AnnotationFilterPanel( filterBox, -1, annotator=self.annotator, filter_callback=self.onFilter, filter_by_book=not self.reader.ready, ) # Translators: header of a group of controls in a dialog to view user's comments/highlights sortBox = make_sized_static_box(parent, _("Sort By")) sortPanel = sc.SizedPanel(sortBox, -1) sortPanel.SetSizerType("horizontal") sortPanel.SetSizerProps(expand=True) sort_options = [ # Translators: text of a toggle button to sort comments/highlights list (_("Date"), AnnotationSortCriteria.Date), # Translators: text of a toggle button to sort comments/highlights list (_("Page"), AnnotationSortCriteria.Page), ] if not self.reader.ready: # Translators: text of a toggle button to sort comments/highlights list sort_options.append((_("Book"), AnnotationSortCriteria.Book)) for bt_label, srt_criteria in sort_options: tglButton = wx.ToggleButton(sortPanel, -1, bt_label) self._sort_toggles[tglButton] = srt_criteria self.Bind(wx.EVT_TOGGLEBUTTON, self.onSortToggle, tglButton) # Translators: text of a toggle button to sort comments/highlights list self.sortMethodToggle = wx.ToggleButton(sortPanel, -1, _("Ascending")) wx.StaticText(parent, -1, self.Title) self.itemsView = ImmutableObjectListView( parent, id=wx.ID_ANY, style=wx.LC_REPORT | wx.SUNKEN_BORDER ) self.itemsView.SetSizerProps(expand=True) self.buttonPanel = sc.SizedPanel(parent, -1) self.buttonPanel.SetSizerType("horizontal") # Translators: text of a button in a dialog to view comments/highlights wx.Button(self.buttonPanel, wx.ID_PREVIEW, _("&View...")) if self.can_edit: # Translators: text of a button in a dialog to view comments/highlights wx.Button(self.buttonPanel, wx.ID_EDIT, _("&Edit...")) self.Bind(wx.EVT_BUTTON, self.onEdit, id=wx.ID_EDIT) # Translators: text of a button in a dialog to view comments/highlights wx.Button(self.buttonPanel, wx.ID_DELETE, _("&Delete...")) # Translators: text of a button in a dialog to view comments/highlights exportButton = wx.Button(self.buttonPanel, -1, _("E&xport...")) self.Bind(wx.EVT_TOGGLEBUTTON, self.onSortMethodToggle, self.sortMethodToggle) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.onItemClick, self.itemsView) self.Bind(wx.EVT_LIST_KEY_DOWN, self.onKeyDown, self.itemsView) self.Bind(wx.EVT_BUTTON, self.onView, id=wx.ID_PREVIEW) self.Bind(wx.EVT_BUTTON, self.onDelete, id=wx.ID_DELETE) self.Bind(wx.EVT_BUTTON, self.onExport, exportButton) self.on_filter_and_sort_state_changed() self.set_items() def get_items(self): getter_func = ( self.annotator.get_for_book if self.reader.ready else self.annotator.get_all ) return getter_func( self._filter_and_sort_state.filter_criteria, self._filter_and_sort_state.sort_criteria, self._filter_and_sort_state.asc, ) def set_items(self, items=None): items = items or self.get_items() self.itemsView.set_columns(self.column_defn()) self.itemsView.set_objects(items) self.itemsView.SetFocusFromKbd() if not self.itemsView.ItemCount: self.buttonPanel.Disable() def on_filter_and_sort_state_changed(self): self.set_items(self.get_items()) self.sortMethodToggle.SetValue(self._filter_and_sort_state.asc) for btn, sort_criteria in self._sort_toggles.items(): if self._filter_and_sort_state.sort_criteria is sort_criteria: btn.SetValue(True) else: btn.SetValue(False) def onFilter(self, book_id, tag, section_title, content): self._filter_and_sort_state.filter_criteria = AnnotationFilterCriteria( book_id=book_id, tag=tag, section_title=section_title, content_snip=content ) self.on_filter_and_sort_state_changed() def onSortToggle(self, event): if event.IsChecked(): event.GetEventObject().SetValue(False) self._filter_and_sort_state.sort_criteria = self._sort_toggles[ event.GetEventObject() ] self.on_filter_and_sort_state_changed() def onSortMethodToggle(self, event): self._filter_and_sort_state.asc = event.IsChecked() self.on_filter_and_sort_state_changed() def go_to_item(self, item): self.reader.go_to_page(item.page_number) def onItemClick(self, event): item = self.itemsView.get_selected() if item is not None: self.Close() self.go_to_item(item) def view_or_edit(self, is_viewing=True): item = self.itemsView.get_selected() if item is None: return wx.Bell() editable = self.can_edit and not is_viewing dlg = ViewAndEditAnnotationDialog( self, # Translators: title of a dialog to view or edit a single comment/highlight title=_("Editing") if editable else _("View"), annotation=item, editable=editable, ) with dlg: return dlg.ShowModal() def onView(self, event): self.view_or_edit(is_viewing=True) def onDelete(self, event): item = self.itemsView.get_selected() if item is None: return if ( wx.MessageBox( # Translators: content of a message asking the user if they want to delete a comment/highlight _( "This action can not be reverted.\r\nAre you sure you want to remove this item?" ), # Translators: title of a message asking the user if they want to delete a bookmark _("Delete Annotation?"), parent=self, style=wx.YES_NO | wx.ICON_WARNING, ) == wx.YES ): self.annotator.delete(item.id) self.filterPanel.update_choices() self.set_items(self.get_items()) def onEdit(self, event): if not self.can_edit: return updates = self.view_or_edit(is_viewing=False) if updates: item = self.itemsView.get_selected() self.annotator.update(item.id, **updates) self.filterPanel.update_choices() self.set_items() def onKeyDown(self, event): item = self.itemsView.get_selected() if item is None: return kcode = event.GetKeyCode() if kcode == wx.WXK_DELETE: self.onDelete(event) elif kcode == wx.WXK_F6: self.filterPanel.SetFocus() elif kcode == wx.WXK_F2: self.edit_tags(item) elif wx.GetKeyState(wx.WXK_CONTROL) and (kcode == 67): try: if get_clipboard_text() != item.content: copy_to_clipboard(item.content) sounds.clipboard.play() except: log.exception( "Failed to copy annotation text to the clipboard", evc_info=True ) event.Skip() def edit_tags(self, item): new_tags = self.service.view.get_text_from_user( # Translators: title of a dialog that allows the user to edit the tag set of a comment/highlight title=_("Edit Tags"), # Translators: label of an edit control that allows the user to edit the tag set of a comment/highlight label=_("Tags"), value=" ".join(item.tags), ) if new_tags is not None: self.annotator.update(item.id, tags=[t.strip() for t in new_tags.split()]) self.filterPanel.update_choices() def onExport(self, event): items = tuple(self.get_items()) # Translators: title of a dialog that allows the user to customize # how comments/highlights are exported with ExportNotesDialog(parent=self, title=_("Export Options")) as dlg: retval = dlg.ShowModal() if retval is None: return wx.Bell() renderer_cls, open_after_export, export_options = retval self.export_items(renderer_cls, items, export_options, open_after_export) def export_items(self, renderer_cls, items, export_options, open_after_export): renderer = renderer_cls( items, export_options, self._filter_and_sort_state.filter_criteria ) resulting_file = renderer.render_to_file() if open_after_export: wx.LaunchDefaultApplication(resulting_file)
class BookmarksViewer(SimpleDialog): """A dialog to view the bookmarks of the current book.""" def __init__(self, reader, annotator, *args, **kwargs): self.view = reader.view self.reader = reader self.annotator = annotator(self.reader) # Translators: label for unnamed bookmarks shown # when editing a single bookmark which has no name self._unamed_bookmark_title = _("[Unnamed Bookmark]") super().__init__(*args, **kwargs) def addControls(self, parent): # Translators: label of a list control containing bookmarks wx.StaticText(parent, -1, _("Saved Bookmarks")) self.annotationsListCtrl = ImmutableObjectListView(parent, wx.ID_ANY) # Translators: text of a button to remove bookmarks wx.Button(parent, wx.ID_DELETE, _("&Remove")) self.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.onItemClick, self.annotationsListCtrl ) self.Bind(wx.EVT_LIST_KEY_DOWN, self.onKeyDown, self.annotationsListCtrl) self.Bind( wx.EVT_LIST_END_LABEL_EDIT, self.onEndLabelEdit, self.annotationsListCtrl ) self.Bind(wx.EVT_BUTTON, self.onDelete, id=wx.ID_DELETE) wx.FindWindowById(wx.ID_DELETE).Enable(False) self._populate_list() def getButtons(self, parent): btnsizer = wx.StdDialogButtonSizer() # Translators: the label of a button to close a dialog btnsizer.AddButton(wx.Button(self, wx.ID_CANCEL, _("&Close"))) btnsizer.Realize() return btnsizer def _populate_list(self, focus_target=0): annotations = self.annotator.get_for_book() column_defn = [ ColumnDefn( # Translators: the title of a column in the bookmarks list _("Name"), "left", 250, lambda bk: bk.title or self._unamed_bookmark_title, ), ColumnDefn( # Translators: the title of a column in the bookmarks list _("Page"), "center", 150, lambda bk: bk.page_number + 1, ), ] if self.reader.document.has_toc_tree(): # Translators: the title of a column in the bookmarks list column_defn.append(ColumnDefn(_("Section"), "left", 250, "section_title")) self.annotationsListCtrl.set_columns(column_defn) self.annotationsListCtrl.set_objects(annotations) self.FindWindowById(wx.ID_DELETE).Enable(len(annotations)) def onItemClick(self, event): item = self.annotationsListCtrl.get_selected() if item is None: return self.reader.go_to_page(item.page_number) self.Close() wx.CallAfter(self.parent.contentTextCtrl.SetFocusFromKbd) wx.CallAfter(self.parent.contentTextCtrl.SetInsertionPoint, item.position) def onKeyDown(self, event): item = self.annotationsListCtrl.get_selected() if item is None: return selected_idx = self.annotationsListCtrl.GetFocusedItem() kcode = event.GetKeyCode() if kcode == wx.WXK_F2: editCtrl = self.annotationsListCtrl.EditLabel(selected_idx) if ( self.annotationsListCtrl.GetItemText(selected_idx) == self._unamed_bookmark_title ): editCtrl.SetValue("") elif kcode == wx.WXK_DELETE: self.onDelete(event) event.Skip() def onEndLabelEdit(self, event): newTitle = event.GetLabel() if newTitle != self._unamed_bookmark_title: self.annotator.update( item_id=self.annotationsListCtrl.get_selected().id, title=newTitle ) def onDelete(self, event): from . import AnnotationService item = self.annotationsListCtrl.get_selected() if item is None: return if ( wx.MessageBox( # Translators: content of a message asking the user if they want to delete a bookmark _( "This action can not be reverted.\r\nAre you sure you want to remove this bookmark?" ), # Translators: title of a message asking the user if they want to delete a bookmark _("Remove Bookmark?"), parent=self, style=wx.YES_NO | wx.ICON_WARNING, ) == wx.YES ): page_number, pos = item.page_number, item.position self.annotator.delete(item.id) self._populate_list() if page_number == self.reader.current_page: AnnotationService.style_bookmark(self.Parent, pos, enable=False)
class TesseractLanguagePanel(sc.SizedPanel): def __init__(self, *args, is_offline, **kwargs): super().__init__(*args, **kwargs) self.is_offline = is_offline self.online_languages = tesseract_download.get_downloadable_languages() # Translators: label of a list control containing bookmarks wx.StaticText(self, -1, _("Tesseract Languages")) listPanel = sc.SizedPanel(self) listPanel.SetSizerType("horizontal") listPanel.SetSizerProps(expand=True, align="center") self.tesseractLanguageList = ImmutableObjectListView( listPanel, wx.ID_ANY, style=wx.LC_REPORT | wx.SUNKEN_BORDER, size=(500, -1)) self.btnPanel = btnPanel = sc.SizedPanel(self, -1) btnPanel.SetSizerType("horizontal") btnPanel.SetSizerProps(expand=True) if not self.is_offline: # Translators: text of a button to add a language to Tesseract OCR Engine (best quality model) self.addBestButton = wx.Button(btnPanel, wx.ID_ANY, _("Download &Best Model")) # Translators: text of a button to add a language to Tesseract OCR Engine (fastest model) self.addFastButton = wx.Button(btnPanel, wx.ID_ANY, _("Download &Fast Model")) self.Bind(wx.EVT_BUTTON, self.onAdd, self.addFastButton) self.Bind(wx.EVT_BUTTON, self.onAdd, self.addBestButton) else: # Translators: text of a button to remove a language from Tesseract OCR Engine self.removeButton = wx.Button(btnPanel, wx.ID_REMOVE, _("&Remove")) self.Bind(wx.EVT_BUTTON, self.onRemove, id=wx.ID_REMOVE) self.tesseractLanguageList.Bind(wx.EVT_SET_FOCUS, self.onListFocus, self.tesseractLanguageList) def populate_list(self, set_focus=True): installed_languages = [(True, info) for info in sorted( TesseractOcrEngine.get_recognition_languages(), key=lambda l: l.english_name, )] if self.is_offline: languages = installed_languages else: languages = [] added_locale_infos = set(l[1] for l in installed_languages) for lang in self.online_languages: loc_info = LocaleInfo.from_three_letter_code(lang) if loc_info in added_locale_infos: continue else: languages.append((False, loc_info)) added_locale_infos.add(loc_info) column_defn = [ ColumnDefn( # Translators: the title of a column in the Tesseract language list _("Language"), "left", 450, lambda lang: lang[1].description, ), ColumnDefn( # Translators: the title of a column in the Tesseract language list _("Installed"), "center", 100, lambda lang: _("Yes") if lang[0] else _("No"), ), ] self.tesseractLanguageList.set_columns(column_defn) if set_focus: self.tesseractLanguageList.set_objects(languages, focus_item=0) else: self.tesseractLanguageList.set_objects(languages, set_focus=False) # Maintain the state of the list if not any(languages): if not self.is_offline: self.addBestButton.Enable(False) self.addFastButton.Enable(False) else: self.removeButton.Enable(False) self.btnPanel.Enable(False) def onAdd(self, event): if (selected := self.tesseractLanguageList.get_selected()) is None: return lang = selected[1] variant = "best" if event.GetEventObject( ) == self.addBestButton else "fast" lang_code = lang.given_locale_name if lang_code not in self.online_languages: log.debug(f"Could not find download info for language {lang_code}") return target_file = tesseract_download.get_language_path(lang_code) if target_file.exists(): msg = wx.MessageBox( # Translators: content of a messagebox _("A version of the selected language model already exists.\n" "Are you sure you want to replace it."), # Translators: title of a message box _("Confirm"), style=wx.YES_NO | wx.ICON_WARNING, parent=self, ) if msg == wx.NO: return try: target_file.unlink(missing_ok=True) except: return progress_dlg = RobustProgressDialog( wx.GetApp().mainFrame, # Translators: title of a progress dialog _("Downloading Language"), # Translators: content of a progress dialog _("Getting download information..."), maxvalue=100, can_hide=True, can_abort=True, ) threaded_worker.submit( tesseract_download.download_language, lang_code, variant, target_file, progress_dlg, ).add_done_callback(lambda future: wx.CallAfter( self._after_download_language, progress_dlg, future))