def on_js_message(handled, msg, context): if isinstance(context, CardLayout) and (msg.startswith("ct_click_") or msg.startswith("ct_dblclick_")): # card layout is a modal dialog, so we can't display there tooltip("Can't be used in card layout screen.") return handled if not isinstance(context, Reviewer) and not isinstance( context, PreviewDialog): # only function in review and preview screens return handled if msg.startswith("ct_click_"): tag = msg.replace("ct_click_", "") browser = dialogs.open("Browser", mw) browser.setFilter('"tag:%s"' % tag) return True, None elif msg.startswith("ct_dblclick_"): tag, deck = msg.replace("ct_dblclick_", "").split("|") browser = dialogs.open("Browser", mw) browser.setFilter('"tag:%s" "deck:%s"' % (tag, deck)) browser.setWindowState(browser.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) return True, None return handled
def switchAddWindow(self): curDialogs = dialogs._dialogs # toggle between windows if curDialogs["AddCards"][1] == self.parentWindow: dialogs.open("AddCards2", self.mw) else: dialogs.open("AddCards", self.mw)
def linkHandler(self, url, _old): if url.startswith('ct_click_'): tag = url.replace('ct_click_', '') browser = dialogs.open('Browser', self.mw) browser.setFilter('"tag:%s"' % tag) elif url.startswith('ct_dblclick_'): tag, deck = url.replace('ct_dblclick_', '').split('|') browser = dialogs.open('Browser', self.mw) browser.setFilter('"tag:%s" "deck:%s"' % (tag, deck)) browser.setWindowState(browser.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) else: return _old(self, url)
def browseMissingMedia(self, nohave, diag): #dialog blocks browser from being usable diag.close() from aqt import mw, dialogs browser = dialogs.open("Browser", mw, False) browser.form.searchEdit.lineEdit().setText("tag:MissingMedia") browser.onSearchActivated()
def onEdit(self): """ This function needs to set the leech dialog to non-modal so the user can interact with the edit window. This actually only allows the user to interact with the editor -- it's not possible to click the "resume editing" button in the main window for example. I don't understand why, but it works fine to set the dialog to non-modal permanently here, but it doesn't work if the dialog is set to non-modal in the constructor! In order to make sure the user can't do funny things by pressing a button in the leech dialog while the editor is still open, we hide all the buttons and block reject. Then we temporarily wrap the close-window method in aqt to toggle the buttons back on (the normal version is restored as soon as it is called once on the edit-current dialog). """ dlg = dialogs.open("EditCurrent", mw) oldCloseDlg = dialogs.close def newCloseDlg(name): if name == "EditCurrent": dialogs.close = oldCloseDlg # restore old functionality self._toggleDlgEnabled() oldCloseDlg(name) dialogs.close = newCloseDlg self.setModal(False) self._toggleDlgEnabled()
def handle_kanji_command(handled, cmd, context): if not cmd.startswith(kLinkPrefix): return handled search = 'kanji:' + cmd[len(kLinkPrefix):].strip() browser = dialogs.open("Browser", mw) browser.form.searchEdit.lineEdit().setText(search) browser.onSearchActivated() return (True, None)
def searchSelected(self, in_browser): if in_browser: b = dialogs.open('Browser', self.dictInt.mw) b.form.searchEdit.lineEdit().setText('Expression:*{0}*'.format( self.selectedText())) b.onSearchActivated() else: self.dictInt.initSearch(self.selectedText())
def on_bridge_browser(handled, cmd, context): prefix = "Browser search:" if not cmd.startswith(prefix): return handled search = cmd[len(prefix):] browser = dialogs.open("Browser", mw) browser.form.searchEdit.lineEdit().setText(search) browser.onSearchActivated() return (True, None)
def do_browser_search(self, extra_search=""): # Use the current line's text or the last line if the current one is an empty line note_tags = self.current_tags_list() searched_tag = self.form.listWidget.currentItem().text() or (note_tags[-1] if len(note_tags)>0 else "") if searched_tag: browser = dialogs.open('Browser', mw) browser.setFilter('tag:"{}*" {}'.format(searched_tag, extra_search)) self.accept() else: tooltip("empty tag was selected for search")
def browseSameFocus( self ): #3 '''Opens browser and displays all notes with the same focus morph. Useful to quickly find alternative notes to learn focus from''' try: n = self.card.note() if not focus( n ): return q = '%s:%s' % ( focusName( n ), focus( n ) ) b = dialogs.open( 'Browser', self.mw ) b.form.searchEdit.lineEdit().setText( q ) b.onSearch() except KeyError: pass
def browseSameFocus( self ): #3 '''Opens browser and displays all notes with the same focus morph. Useful to quickly find alternative notes to learn focus from''' try: n = self.card.note() if not focus( n ): return q = u'%s:%s' % ( focusName( n ), focus( n ) ) b = dialogs.open( 'Browser', self.mw ) b.form.searchEdit.lineEdit().setText( q ) b.onSearch() except KeyError: pass
def onDelete(): global cids cids = set(cids) #change here to make a set saveGeom(diag, "emptyCards") QDialog.accept(diag) self.checkpoint(_("Delete Empty")) # Beginning of changes nidToCidsToDelete = dict() for cid in cids: card = self.col.getCard(cid) nid = card.note().id if nid not in nidToCidsToDelete: # print("note %s not yet in nidToCidsToDelete. Thus adding it"%nid) nidToCidsToDelete[nid] = 0 # else: # print("note %s already in nidToCidsToDelete."%nid) nidToCidsToDelete[nid] += 1 # print("Adding card %s to note %s."%(cid,nid)) emptyNids = 0 for nid in nidToCidsToDelete: note = self.col.getNote(nid) cidsOfNids = len(note.cards()) if cidsOfNids <= nidToCidsToDelete[nid]: emptyNids += 1 note.addTag("NoteWithNoCard") note.flush() cids -= set([note.cards()[0].id]) #keep one card # else # cloze type or normal delete # unlike note types, cloze types are never totally removed. self.col.remCards(cids, notes=False) nidsWithTag = set(self.col.findNotes("tag:NoteWithNoCard")) # print("emptyNids is %s, nidsWithTag is %s"%(emptyNids,nidsWithTag)) if emptyNids: showWarning( """%d note(s) should have been deleted because they had no more cards. They now have the tag "NoteWithNoCard". Please go check them. Then either edit them to save their content, or delete them from the browser.""" % emptyNids) browser = dialogs.open("Browser", mw) browser.form.searchEdit.lineEdit().setText("tag:NoteWithNoCard") # end of changes tooltip( ngettext("%d card deleted.", "%d cards deleted.", len(cids)) % len(cids)) self.reset()
def add_related_note(related_note_id, model_id, deck_id, fields_to_copy, copy_tags, browser): browser.col.decks.select(deck_id) current_deck = browser.col.decks.current() current_deck['mid'] = model_id browser.col.decks.save(current_deck) browser.col.models.setCurrent(browser.col.models.get(model_id)) note_to_copy = browser.col.getNote(related_note_id) add_cards: addcards.AddCards = dialogs.open('AddCards', mw) new_note = add_cards.editor.note if copy_tags: new_note.tags = note_to_copy.tags for field in fields_to_copy: new_note[field] = note_to_copy[field] add_cards.setAndFocusNote(new_note)
def browseSameFocus(self): # 3 """Opens browser and displays all notes with the same focus morph. Useful to quickly find alternative notes to learn focus from""" try: n = self.card.note() focusMorphs = focus(n) if len(focusMorphs) == 0: return q = focusQuery(focusName(), focusMorphs) b = dialogs.open('Browser', self.mw) b.form.searchEdit.lineEdit().setText(q) b.onSearchActivated() except KeyError: pass
def handle_click(handled, msg, context): if isinstance(context, CardLayout) and (msg.startswith('ct_click_') or msg.startswith('ct_dblclick_')): tooltip("Can't be used in card layout screen.") return handled if not isinstance(context, Reviewer) and not isinstance( context, PreviewDialog): return handled if msg.startswith('ct_click_'): tag = msg.replace('ct_click_', '') browser = dialogs.open('Browser', mw) browser.setFilter('"tag:%s"' % tag) return True, None elif msg.startswith('ct_dblclick_'): tag, deck = msg.replace('ct_dblclick_', '').split('|') browser = dialogs.open('Browser', mw) browser.setFilter('"tag:%s" "deck:%s"' % (tag, deck)) browser.setWindowState(browser.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) return True, None return handled
def onDelete(): nonlocal cids saveGeom(diag, "emptyCards") QDialog.accept(diag) self.checkpoint(_("Delete Empty")) # Beginning of changes nidToCidsToDelete = dict() for cid in cids: card = self.col.getCard(cid) note = card.note() nid = note.id if nid not in nidToCidsToDelete: nidToCidsToDelete[nid] = set() nidToCidsToDelete[nid].add(cid) emptyNids = set() cardsOfEmptyNotes = set() for nid, cidsToDeleteOfNote in nidToCidsToDelete.items(): note = self.col.getNote(nid) cidsOfNids = set([card.id for card in note.cards()]) if cidsOfNids == cidsToDeleteOfNote: emptyNids.add(note.id) cids -= cidsOfNids self.col.remCards(cids, notes=False) nidsWithTag = set(self.col.findNotes("tag:NoteWithNoCard")) for nid in emptyNids - nidsWithTag: note = self.col.getNote(nid) note.addTag("NoteWithNoCard") note.flush() for nid in nidsWithTag - emptyNids: note = self.col.getNote(nid) note.delTag("NoteWithNoCard") note.flush() if emptyNids: showWarning( f"""{len(emptyNids)} note(s) should have been deleted because they had no more cards. They now have the tag "NoteWithNoCard". Please go check them. Then either edit them to save their content, or delete them from the browser.""" ) browser = dialogs.open("Browser", mw) browser.form.searchEdit.lineEdit().setText("tag:NoteWithNoCard") browser.onSearchActivated() # end of changes tooltip( ngettext("%d card deleted.", "%d cards deleted.", len(cids)) % len(cids)) self.reset()
def onAdd(self): dialogs.open("AddCards", mw) self.setModal(False)
def onDelete(mw, diag, cids): p(f"Calling new onDelete with cids {cids}") cids = set(mw.col.emptyCids()) #change here to make a set saveGeom(diag, "emptyCards") QDialog.accept(diag) mw.checkpoint(_("Delete Empty")) # Beginning of changes nidToCidsToDelete = dict() for cid in cids: card = mw.col.getCard(cid) note = card.note() nid = note.id if nid not in nidToCidsToDelete: p(f"note {nid} not yet in nidToCidsToDelete. Thus adding it") nidToCidsToDelete[nid] = set() else: p(f"note {nid} already in nidToCidsToDelete.") nidToCidsToDelete[nid].add(cid) p(f"Adding card {cid} to note {nid}.") emptyNids = set() cardsOfEmptyNotes = set() for nid, cidsToDeleteOfNote in nidToCidsToDelete.items(): note = mw.col.getNote(nid) cidsOfNids = set([card.id for card in note.cards()]) p(f"In note {nid}, the cards are {cidsOfNids}, and the cards to delete are {cidsToDeleteOfNote}" ) if cidsOfNids == cidsToDeleteOfNote: p(f"Both sets are equal") emptyNids.add(note.id) cids -= cidsOfNids else: p(f"Both sets are different") mw.col.remCards(cids, notes=False) nidsWithTag = set(mw.col.findNotes("tag:NoteWithNoCard")) p(f"emptyNids is {emptyNids}, nidsWithTag is {nidsWithTag}") for nid in emptyNids - nidsWithTag: note = mw.col.getNote(nid) note.addTag("NoteWithNoCard") p(f"Adding tag to note {note.id}") note.flush() for nid in nidsWithTag - emptyNids: note = mw.col.getNote(nid) # TODO: If there's only 1 note, this method is never triggered. # So the tag stays. note.delTag("NoteWithNoCard") p(f"Removing tag from note {note.id}") note.flush() if emptyNids: showWarning( f"""{len(emptyNids)} note(s) should have been deleted because they had no more cards. They now have the tag "NoteWithNoCard". Please go check them. Then either edit them to save their content, or delete them from the browser.""" ) browser = dialogs.open("Browser", mw, False) browser.form.searchEdit.lineEdit().setText("tag:NoteWithNoCard") browser.onSearchActivated() # end of changes tooltip( ngettext("%d card deleted.", "%d cards deleted.", len(cids)) % len(cids)) mw.reset()
def handle_doubleclick(self, index): nid = self.model.data(index, NID_Role) browser = dialogs.open('Browser', mw) # we shouldn't do this but idk if there is a better way browser._lastSearchTxt = "nid:" + str(nid) browser.model.search("nid:" + str(nid))
def add_browser_search_link(self, cmd: str) -> Any: if cmd.startswith("browserSearch"): _, query = cmd.split(":", 1) browser = dialogs.open("Browser", self.mw) browser.search_for(query)
def showBrowser(nid): browser = dialogs.open('Browser', mw) browser.form.searchEdit.lineEdit().setText('nid:' + str(nid)) browser.onSearchActivated()
def check(self, local=None): "Return (missingFiles, unusedFiles)." mdir = self.dir() # gather all media references in NFC form allRefs = set() refsToNid = dict() # this dic is new for nid, mid, flds in self.col.db.execute( "select id, mid, flds from notes"): noteRefs = self.filesInStr(mid, flds) # check the refs are in NFC for f in noteRefs: # if they're not, we'll need to fix them first if f != unicodedata.normalize("NFC", f): self._normalizeNoteRefs(nid) noteRefs = self.filesInStr(mid, flds) break # new. update refsToNid for f in noteRefs: if f not in refsToNid: refsToNid[f] = set() refsToNid[f].add(nid) # end new allRefs.update(noteRefs) # loop through media folder unused = [] if local is None: files = os.listdir(mdir) else: files = local renamedFiles = False dirFound = False warnings = [] for file in files: if not local: if not os.path.isfile(file): # ignore directories dirFound = True continue if file.startswith("_"): # leading _ says to ignore file continue if self.hasIllegal(file): name = file.encode(sys.getfilesystemencoding(), errors="replace") name = str(name, sys.getfilesystemencoding()) warnings.append(_("Invalid file name, please rename: %s") % name) continue nfcFile = unicodedata.normalize("NFC", file) # we enforce NFC fs encoding on non-macs if not isMac and not local: if file != nfcFile: # delete if we already have the NFC form, otherwise rename if os.path.exists(nfcFile): os.unlink(file) renamedFiles = True else: os.rename(file, nfcFile) renamedFiles = True file = nfcFile # compare if nfcFile not in allRefs: unused.append(file) else: allRefs.discard(nfcFile) # if we renamed any files to nfc format, we must rerun the check # to make sure the renamed files are not marked as unused if renamedFiles: return self.check(local=local) # NEW: A line here removed because it was a bug # New finder = Finder(mw.col) alreadyMissingNids = finder.findNotes("tag:MissingMedia") nidsOfMissingRefs = set() for ref in allRefs: nidsOfMissingRefs.update(refsToNid[ref]) #print(f"nidsOfMissingRefs is now {nidsOfMissingRefs}") for nid in nidsOfMissingRefs: if nid not in alreadyMissingNids: print(f"missing nid {nid}") note = Note(mw.col, id=nid) note.addTag("MissingMedia") note.flush() for nid in alreadyMissingNids: if nid not in nidsOfMissingRefs: print(f"not missing anymore nid {nid}") note = Note(mw.col, id=nid) note.delTag("MissingMedia") note.flush() # end new # make sure the media DB is valid try: self.findChanges() except DBError: self._deleteDB() if dirFound: warnings.append( _("Anki does not support files in subfolders of the collection.media folder." )) if allRefs: browser = dialogs.open("Browser", mw) browser.form.searchEdit.lineEdit().setText("tag:MissingMedia") browser.onSearchActivated() return (allRefs, unused, warnings)
def browseCards(cids): from aqt import dialogs browser = dialogs.open("Browser", self, False) browser.form.searchEdit.lineEdit().setText("cid:%s"%ids2str(cids)) browser.onSearchActivated()