def toggle_search_highlights(browser: Browser, checked: bool): """Toggle search highlights on or off""" browser._highlight_results = checked if not checked: clear_highlights(browser.editor.web) else: on_browser_did_change_row(browser)
def _on_edit_window(browser: Browser) -> bool: """Launch BrowserEditCurrent instance""" cids = browser.selectedCards() if not cids or not browser.card: tooltip("No cards selected") return False elif len(cids) > 1: tooltip("Please select just one card") return False hide_browser_editor(browser) browser.external_editor = aqt.dialogs.open("BrowserEditCurrent", browser.mw, browser, browser.card) return True
def on_bulk_convert(browser: Browser): selected_nids = browser.selectedNotes() if selected_nids: dialog = BulkConvertDialog(browser) if dialog.exec(): bulk_convert(browser, selected_nids, dialog.selected_fields()) else: tooltip("No cards selected.")
def on_batch_edit(browser: Browser) -> None: """ Open BatchEditDialog when menu entry is clicked. :param browser: Anki browser """ selected_notes = browser.selectedNotes() if not selected_notes: tooltip("No cards selected.") return dialog = AddIpaTranscriptDialog(browser, selected_notes) dialog.exec_()
def on_browser_menus_did_init(browser: Browser): """Setup menu entries and hotkeys""" browser._highlight_results = config["local"]["highlight_by_default"] try: # used by multiple add-ons, so we check for its existence first menu = browser.menuView except AttributeError: browser.menuView = QMenu("&View") browser.menuBar().insertMenu(browser.mw.form.menuTools.menuAction(), browser.menuView) menu = browser.menuView menu.addSeparator() a = menu.addAction("Highlight Search Results") a.setCheckable(True) a.setChecked(browser._highlight_results) a.setShortcut(QKeySequence(config["local"]["hotkey_toggle_highlights"])) a.toggled.connect( lambda toggled: toggle_search_highlights(browser, toggled))
def on_merge_selected(browser: Browser) -> None: cids = browser.selectedCards() if len(cids) < 2: tooltip("At least two cards must be selected.") return browser.model.beginReset() browser.mw.checkpoint(_("Merge fields of selected cards")) merge_cards_fields(cids) browser.model.endReset() browser.mw.reset() tooltip(f"{len(cids)} cards merged.", parent=browser)
def on_run_ocr(browser: Browser): selected_nids = browser.selectedNotes() num_notes = len(selected_nids) config = mw.addonManager.getConfig(__name__) if num_notes == 0: showInfo("No cards selected.") return elif askUser( f"Are you sure you wish to run OCR processing on {num_notes} notes?" ) is False: return if config.get("tesseract_install_valid") is not True and config.get( "text_output_location") == "new_field": showInfo( f"Note that because this addon changes the note template, you will see a warning about changing the database and uploading to AnkiWeb. \n" f"This is normal, and will be shown each time you modify a note template.\n" f"This message will be only be shown once.") mw.addonManager.writeConfig(__name__, config) config[ "tesseract_install_valid"] = True # Stop the above msg appearing multiple times progress = mw.progress ocr = OCR(col=mw.col, progress=progress, languages=config["languages"]) progress.start(immediate=True, min=0, max=num_notes) try: ocr.run_ocr_on_notes(note_ids=selected_nids, overwrite_existing=config["overwrite_existing"]) progress.finish() showInfo(f"Processed OCR for {num_notes} cards") except pytesseract.TesseractNotFoundError: progress.finish() showCritical( text=f"Could not find a valid Tesseract-OCR installation! \n" f"Please visit the addon page in at https://ankiweb.net/shared/info/450181164 for" f" install instructions") except Exception as errmsg: progress.finish() showCritical( f"Error encountered during processing, attempting to stop AnkiOCR gracefully. Error below:\n" f"{errmsg}") finally: browser.model.reset() mw.requireReset()
def on_rm_ocr_fields(browser: Browser): config = mw.addonManager.getConfig(__name__) selected_nids = browser.selectedNotes() num_notes = len(selected_nids) if num_notes == 0: showInfo("No cards selected.") return elif askUser(f"Are you sure you wish to remove the OCR field from {num_notes} notes?") is False: return progress = mw.progress progress.start(immediate=True) ocr = OCR(col=mw.col, progress=progress, languages=config["languages"]) ocr.remove_ocr_on_notes(note_ids=selected_nids) mw.progress.finish() browser.model.reset() mw.requireReset() log_messages = logger.handlers[0].flush() showInfo(f"Removed the OCR field from {num_notes} cards\n" f"{log_messages}")
def on_run_ocr(browser: Browser): time_start = time.time() selected_nids = browser.selectedNotes() config = mw.addonManager.getConfig(__name__) num_notes = len(selected_nids) num_batches = ceil(num_notes / config["batch_size"]) if num_notes == 0: showInfo("No cards selected.") return elif askUser(f"Are you sure you wish to run OCR processing on {num_notes} notes?") is False: return if config.get("tesseract_install_valid") is not True and config.get("text_output_location") == "new_field": showInfo( f"Note that because this addon changes the note template, you will see a warning about changing the " f"database and uploading to AnkiWeb. \n " f"This is normal, and will be shown each time you modify a note template.\n" f"This message will be only be shown once.") config["tesseract_install_valid"] = True # Stop the above msg appearing multiple times mw.addonManager.writeConfig(__name__, config) try: progress = mw.progress progress.start(immediate=True, min=0, max=num_batches) progress.update(value=0, max=num_batches, label="Starting OCR processing...") except TypeError: # old version of Qt/Anki progress = None ocr = OCR(col=mw.col, progress=progress, languages=config["languages"], text_output_location=config["text_output_location"], tesseract_exec_pth=config["tesseract_exec_path"] if config["override_tesseract_exec"] else None, batch_size=config["batch_size"], num_threads=config["num_threads"], use_batching=config["use_batching"], use_multithreading=config["use_multithreading"]) try: ocr.run_ocr_on_notes(note_ids=selected_nids) if progress: progress.finish() time_taken = time.time() - time_start log_messages = logger.handlers[0].flush() showInfo( f"Processed OCR for {num_notes} notes in {round(time_taken, 1)}s ({round(time_taken / num_notes, 1)}s per note)\n" f"{log_messages}") except pytesseract.TesseractNotFoundError: if progress: progress.finish() showCritical(text=f"Could not find a valid Tesseract-OCR installation! \n" f"Please visit the addon page in at https://ankiweb.net/shared/info/450181164 for" f" install instructions") except (RuntimeError, Exception) as exc: from . import __version__ as anki_ocr_version from anki.buildinfo import version as anki_version import sys import platform if progress: progress.finish() msg = f"Error encountered during processing. Debug info: \n" \ f"Anki Version: {anki_version} , AnkiOCR Version: {anki_ocr_version}\n" \ f"Platform: {platform.system()} , Python Version: {sys.version}" log_messages = logger.handlers[0].flush() if len(log_messages) > 0: msg += f"Logging message generated during processing:\n{log_messages}" exception_str: List[str] = traceback.format_exception(etype=type(exc), value=exc, tb=exc.__traceback__) msg += "".join(exception_str) showInfo(msg) finally: browser.model.reset() mw.requireReset()