예제 #1
0
파일: main.py 프로젝트: terrisage/Anki
    def loadCollection(self):
        cpath = self.pm.collectionPath()
        try:
            self.col = Collection(cpath, log=True)
        except anki.db.Error:
            # warn user
            showWarning(_("""\
Your collection is corrupt. Please create a new profile, then \
see the manual for how to restore from an automatic backup.

Debug info:
""")+traceback.format_exc())
            self.unloadProfile()
        except Exception as e:
            # the custom exception handler won't catch this if we immediately
            # unload, so we have to manually handle it
            if "invalidTempFolder" in repr(str(e)):
                showWarning(self.errorHandler.tempFolderMsg())
                self.unloadProfile()
                return
            self.unloadProfile()
            raise
        self.progress.setupDB(self.col.db)
        self.maybeEnableUndo()
        self.moveToState("deckBrowser")
예제 #2
0
    def onTimeout(self):
        error = self.pool
        self.pool = ""
        self.mw.progress.clear()
        if "abortSchemaMod" in error:
            return
        if "Pyaudio not" in error:
            return showWarning(_("Please install PyAudio"))
        if "install mplayer" in error:
            return showWarning(_("Please install mplayer"))
        if "no default output" in error:
            return showWarning(_("Please connect a microphone."))
        stdText = _("""\
An error occurred. It may have been caused by a harmless bug, <br>
or your deck may have a problem.
<p>To confirm it's not a problem with your deck, please run
<b>Tools > Maintenance > Check Database</b>.
<p>If that doesn't fix the problem, please copy the following<br>
into a bug report:""")
        pluginText = _("""\
An error occurred in an add-on. Please contact the add-on author.<br>""")
        if "addon" in error:
            txt = pluginText
        else:
            txt = stdText
        # show dialog
        txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
        showText(txt, type="html")
예제 #3
0
파일: addons.py 프로젝트: terrisage/Anki
    def accept(self):
        QDialog.accept(self)

        # get codes
        try:
            ids = [int(n) for n in self.form.code.text().split()]
        except ValueError:
            showWarning(_("Invalid code."))
            return

        errors = []

        self.mw.progress.start(immediate=True)
        for n in ids:
            ret = download(self.mw, n)
            if ret[0] == "error":
                errors.append(_("Error downloading %(id)s: %(error)s") % dict(id=n, error=ret[1]))
                continue
            data, fname = ret
            self.mw.addonManager.install(data, fname)
        self.mw.progress.finish()
        if not errors:
            tooltip(_("Download successful. Please restart Anki."), period=3000)
        else:
            showWarning("\n".join(errors))
예제 #4
0
파일: addons.py 프로젝트: ChYi/ankiqt
 def __init__(self, mw):
     self.mw = mw
     f = self.mw.form; s = SIGNAL("triggered()")
     self.mw.connect(f.actionOpenPluginFolder, s, self.onOpenPluginFolder)
     self.mw.connect(f.actionEnableAllPlugins, s, self.onEnableAllPlugins)
     self.mw.connect(f.actionDisableAllPlugins, s, self.onDisableAllPlugins)
     if isWin:
         self.clearPluginCache()
     self.disableObsoletePlugins()
     plugdir = self.pluginsFolder()
     sys.path.insert(0, plugdir)
     plugins = self.enabledPlugins()
     plugins.sort()
     self.registeredPlugins = {}
     for plugin in plugins:
         try:
             nopy = plugin.replace(".py", "")
             __import__(nopy)
         except:
             print "Error in %s" % plugin
             traceback.print_exc()
     self.mw.disableCardMenuItems()
     self.rebuildPluginsMenu()
     # run the obsolete init hook
     try:
         runHook('init')
     except:
         showWarning(
             _("Broken plugin:\n\n%s") %
             unicode(traceback.format_exc(), "utf-8", "replace"))
예제 #5
0
    def onChangeDeck(self):
        # based on aqt/browser.py:setDeck(), and add-on writing guide example
        self.mw.checkpoint(_("Suspend"))
        from aqt.studydeck import StudyDeck
        cids = [self.card.id]
        did = self.mw.col.db.scalar(
            "select did from cards where id = ?", cids[0])
        current = self.mw.col.decks.get(did)['name']
        ret = StudyDeck(
            self.mw, current=current, accept=_("Move Cards"),
            title = _("Change Deck"), help="browse", parent=self)
        if not ret.name:
            return
        did = self.mw.col.decks.id(ret.name)
        deck = self.mw.col.decks.get(did)
        if deck['dyn']:
            showWarning(_("Cards can't be manually moved into a filtered deck."))
            return

        self.mw.checkpoint(_("Change deck"))
        self.card.did = did
        # if the card was in a cram deck, we have to put back the original due
        # time and original deck
        self.card.odid = 0
        if self.card.odue:
            self.card.due = self.card.odue
            self.card.odue = 0
        self.accept()
예제 #6
0
파일: errors.py 프로젝트: ACEfanatic02/anki
    def onTimeout(self):
        error = cgi.escape(self.pool)
        self.pool = ""
        self.mw.progress.clear()
        if "abortSchemaMod" in error:
            return
        if "Pyaudio not" in error:
            return showWarning(_("Please install PyAudio"))
        if "install mplayer" in error:
            return showWarning(_("Please install mplayer"))
        if "no default output" in error:
            return showWarning(_("Please connect a microphone, and ensure "
                                 "other programs are not using the audio device."))
        stdText = _("""\
An error occurred. It may have been caused by a harmless bug, <br>
or your deck may have a problem.
<p>To confirm it's not a problem with your deck, please run
<b>Tools &gt; Check Database</b>.
<p>If that doesn't fix the problem, please copy the following<br>
into a bug report:""")
        pluginText = _("""\
An error occurred in an add-on.<br>
Please post on the add-on forum:<br>%s<br>""")
        pluginText %= "https://groups.google.com/forum/#!forum/anki-addons"
        if "addon" in error:
            txt = pluginText
        else:
            txt = stdText
        # show dialog
        txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
        showText(txt, type="html")
예제 #7
0
 def accept(self):
     file = getSaveFile(
         self, _("Export"), "export",
         self.exporter.key, self.exporter.ext)
     self.hide()
     if file:
         self.exporter.includeSched = (
             self.frm.includeSched.isChecked())
         self.exporter.includeMedia = (
             self.frm.includeMedia.isChecked())
         self.exporter.includeTags = (
             self.frm.includeTags.isChecked())
         if not self.frm.deck.currentIndex():
             self.exporter.did = None
         else:
             name = self.decks[self.frm.deck.currentIndex()]
             self.exporter.did = self.col.decks.id(name)
         self.mw.progress.start(immediate=True)
         try:
             f = open(file, "wb")
             f.close()
         except (OSError, IOError), e:
             showWarning(_("Couldn't save file: %s") % unicode(e))
         else:
             os.unlink(file)
             self.exporter.exportInto(file)
             tooltip(_("%d exported.") % self.exporter.count)
         finally:
예제 #8
0
def onExportList(browser):
    # big reach!
    if not browser.form.tableView.selectionModel().hasSelection():
        showWarning("Please select 1 or more rows", browser, help="")
        return
    path = getSaveFile(browser, _("Export Browser List"), "exportcsv", _("Cards as CSV"), '.csv', 'exportcsv.csv')
    if not path:
        return
    file = open(path, "wb")
    writer = csv.writer(file, dialect='excel')

    for rowIndex in browser.form.tableView.selectionModel().selectedRows():
        #wasn't sure if I could modify the "Index" objects we get back from
        #  the selection model. Since the columnData function only accesses
        #  the row() and column() functions, seemed safer to create new
        #  instances.
        row = rowIndex.row()
        rowdata = []
        for column in range(browser.model.columnCount(0)):
            index = RowAndColumn(row, column)
            #let the browser model's columnData function do all the hard work
            answer = escapeText(browser.model.columnData(index))
            rowdata.append(answer.encode('utf8'))
        writer.writerow(rowdata)
    file.close()
예제 #9
0
	def readValues(self):
		mw.EXPORT.FORMAT_INDEX = self.ui.formatCombo.currentIndex()
		delimiter = self.ui.csvEdit.text()
		if mw.EXPORT.FORMAT == "CSV" and mw.EXPORT.CSV_DELIMITER == "":
			showWarning(_("The CSV delimiter is not set"))
			return False
		if delimiter == "\\t":
			mw.EXPORT.CSV_DELIMITER = "\t"
		else:
			mw.EXPORT.CSV_DELIMITER = delimiter
		mw.EXPORT.FILEPATH = self.ui.fileEdit.text()
		if mw.EXPORT.FILEPATH == "":
			showWarning(_("The file name is not set"))
			return False
		mw.EXPORT.FILTER_DECK_INDEX = self.ui.deckFilterCombo.currentIndex()
		mw.EXPORT.FILTER_TAGS = self.ui.tagFilterEdit.text().strip()
		mw.EXPORT.ALL_FIELDS = self.ui.allFieldsCheck.isChecked()
		mw.EXPORT.REVERSE_CARDS = self.ui.reverseCardsCheck.isChecked()
		mw.EXPORT.TAGS = self.ui.allTagsCheck.isChecked()
		mw.EXPORT.DECK_NAME = self.ui.deckNameCheck.isChecked()
		mw.EXPORT.CARD_ID = self.ui.cardIdCheck.isChecked()
		mw.EXPORT.NOTE_ID = self.ui.noteIdCheck.isChecked()
		mw.EXPORT.CARD_TYPE = self.ui.cardTypeCheck.isChecked()
		mw.EXPORT.NOTE_TYPE = self.ui.noteTypeCheck.isChecked()
		return True
예제 #10
0
파일: main.py 프로젝트: terrisage/Anki
 def onOpenProfile(self):
     if not self.openProfile():
         showWarning(_("Invalid password."))
         return
     self.profileDiag.close()
     self.loadProfile()
     return True
예제 #11
0
 def accept(self):
     self.exporter.includeSched = (
         self.frm.includeSched.isChecked())
     self.exporter.includeMedia = (
         self.frm.includeMedia.isChecked())
     self.exporter.includeTags = (
         self.frm.includeTags.isChecked())
     if not self.frm.deck.currentIndex():
         self.exporter.did = None
     else:
         name = self.decks[self.frm.deck.currentIndex()]
         self.exporter.did = self.col.decks.id(name)
     if (self.isApkg and self.exporter.includeSched and not
         self.exporter.did):
         verbatim = True
         # it's a verbatim apkg export, so place on desktop instead of
         # choosing file
         file = os.path.join(QDesktopServices.storageLocation(
             QDesktopServices.DesktopLocation), "collection.apkg")
         if os.path.exists(file):
             if not askUser(
                 _("%s already exists on your desktop. Overwrite it?")%
                 "collection.apkg"):
                 return
     else:
         verbatim = False
         # Get deck name and remove invalid filename characters
         deck_name = self.decks[self.frm.deck.currentIndex()]
         deck_name = re.sub('[\\\\/?<>:*|"^]', '_', deck_name)
         filename = os.path.join(aqt.mw.pm.base,
                                 u'{0}{1}'.format(deck_name, self.exporter.ext))
         while 1:
             file = getSaveFile(self, _("Export"), "export",
                                self.exporter.key, self.exporter.ext,
                                fname=filename)
             if not file:
                 return
             if checkInvalidFilename(os.path.basename(file), dirsep=False):
                 continue
             break
     self.hide()
     if file:
         self.mw.progress.start(immediate=True)
         try:
             f = open(file, "wb")
             f.close()
         except (OSError, IOError), e:
             showWarning(_("Couldn't save file: %s") % unicode(e))
         else:
             os.unlink(file)
             self.exporter.exportInto(file)
             if verbatim:
                 msg = _("A file called collection.apkg was saved on your desktop.")
                 period = 5000
             else:
                 period = 3000
                 msg = ngettext("%d card exported.", "%d cards exported.", \
                             self.exporter.count) % self.exporter.count
             tooltip(msg, period=period)
         finally:
예제 #12
0
파일: importing.py 프로젝트: Stvad/anki
def replaceWithApkg(mw, file, backup):
    # unload collection, which will also trigger a backup
    mw.unloadCollection()
    # overwrite collection
    z = zipfile.ZipFile(file)
    try:
        z.extract("collection.anki2", mw.pm.profileFolder())
    except:
        showWarning(_("The provided file is not a valid .apkg file."))
        return
    # because users don't have a backup of media, it's safer to import new
    # data and rely on them running a media db check to get rid of any
    # unwanted media. in the future we might also want to deduplicate this
    # step
    d = os.path.join(mw.pm.profileFolder(), "collection.media")
    for n, (cStr, file) in enumerate(
            json.loads(z.read("media").decode("utf8")).items()):
        mw.progress.update(ngettext("Processed %d media file",
                                    "Processed %d media files", n) % n)
        size = z.getinfo(cStr).file_size
        dest = os.path.join(d, file)
        # if we have a matching file size
        if os.path.exists(dest) and size == os.stat(dest).st_size:
            continue
        data = z.read(cStr)
        open(dest, "wb").write(data)
    z.close()
    # reload
    mw.loadCollection()
    if backup:
        mw.col.modSchema(check=False)
    mw.progress.finish()
예제 #13
0
파일: upgrade.py 프로젝트: cornercase/anki
    def _copySettings(self):
        p = self.mw.pm.profile
        for k in (
            "recentColours",
            "stripHTML",
            "editFontFamily",
            "editFontSize",
            "editLineSize",
            "deleteMedia",
            "preserveKeyboard",
            "numBackups",
            "proxyHost",
            "proxyPass",
            "proxyPort",
            "proxyUser",
        ):
            try:
                p[k] = self.conf[k]
            except:
                showWarning(
                    _(
                        """\
Anki 2.0 only supports automatic upgrading from Anki 1.2. To load old \
decks, please open them in Anki 1.2 to upgrade them, and then import them \
into Anki 2.0."""
                    )
                )
                return
        return True
예제 #14
0
파일: addcards.py 프로젝트: hoelzro/anki
    def addNote(self, note):
        note.model()["did"] = self.deckChooser.selectedId()
        ret = note.dupeOrEmpty()
        if ret == 1:
            showWarning(_("The first field is empty."), help="AddItems#AddError")
            return
        if "{{cloze:" in note.model()["tmpls"][0]["qfmt"]:
            if not self.mw.col.models._availClozeOrds(note.model(), note.joinedFields(), False):
                if not askUser(
                    _("You have a cloze deletion note type " "but have not made any cloze deletions. Proceed?")
                ):
                    return
        cards = self.mw.col.addNote(note)
        if not cards:
            showWarning(
                _(
                    """\
The input you have provided would make an empty \
question on all cards."""
                ),
                help="AddItems",
            )
            return
        self.addHistory(note)
        self.mw.requireReset()
        return note
예제 #15
0
def nm_on():
	"""
	Turn on night mode.
	"""
	if not nm_profile_loaded:
		showWarning(NM_ERROR_NO_PROFILE)
		return False

	global nm_state_on

	try:
		nm_state_on = True

		import aqt.browser
		aqt.browser.COLOUR_MARKED = "#735083"
		aqt.browser.COLOUR_SUSPENDED = "#777750"

		nm_append_to_styles(nm_css_bottom,
							nm_css_body + nm_card_color_css() + nm_css_custom_color_map(),
							nm_css_top,
							nm_css_decks + nm_body_color_css(),
							nm_css_other_bottoms,
							nm_css_overview() + nm_body_color_css(),
							nm_css_menu,
							nm_css_buttons + nm_body_color_css())
		nm_menu_switch.setChecked(True)
		return True
	except:
		showWarning(NM_ERROR_SWITCH)
		return False
예제 #16
0
파일: downloader.py 프로젝트: Stvad/anki
def download(mw, code):
    "Download addon/deck from AnkiWeb. On success caller must stop progress diag."
    # check code is valid
    try:
        code = int(code)
    except ValueError:
        showWarning(_("Invalid code."))
        return
    # create downloading thread
    thread = Downloader(code)
    def onRecv():
        try:
            mw.progress.update(label="%dKB downloaded" % (thread.recvTotal/1024))
        except NameError:
            # some users report the following error on long downloads
            # NameError: free variable 'mw' referenced before assignment in enclosing scope
            # unsure why this is happening, but guard against throwing the
            # error
            pass
    thread.recv.connect(onRecv)
    thread.start()
    mw.progress.start(immediate=True)
    while not thread.isFinished():
        mw.app.processEvents()
        thread.wait(100)
    if not thread.error:
        # success
        return thread.data, thread.fname
    else:
        mw.progress.finish()
        showWarning(_("Download failed: %s") % thread.error)
예제 #17
0
파일: main.py 프로젝트: terrisage/Anki
    def unloadCollection(self):
        """
        Unload the collection.

        This unloads a collection if there is one and returns True if
        there is no collection after the call. (Because the unload
        worked or because there was no collection to start with.)
        """
        if self.col:
            if not self.closeAllCollectionWindows():
                return
            self.progress.start(immediate=True)
            corrupt = False
            try:
                self.maybeOptimize()
            except:
                corrupt = True
            if not corrupt:
                if os.getenv("ANKIDEV", 0):
                    corrupt = False
                else:
                    corrupt = self.col.db.scalar("pragma integrity_check") != "ok"
            if corrupt:
                showWarning(_("Your collection file appears to be corrupt. \
This can happen when the file is copied or moved while Anki is open, or \
when the collection is stored on a network or cloud drive. Please see \
the manual for information on how to restore from an automatic backup."))
            self.col.close()
            self.col = None
            if not corrupt:
                self.backup()
            self.progress.finish()
        return True
예제 #18
0
파일: addons.py 프로젝트: Glutanimate/anki
 def downloadIds(self, ids):
     log = []
     errs = []
     self.mw.progress.start(immediate=True)
     for n in ids:
         ret = download(self.mw, n)
         if ret[0] == "error":
             errs.append(_("Error downloading %(id)s: %(error)s") % dict(id=n, error=ret[1]))
             continue
         data, fname = ret
         fname = fname.replace("_", " ")
         name = os.path.splitext(fname)[0]
         ret = self.install(io.BytesIO(data),
                            manifest={"package": str(n), "name": name,
                                      "mod": intTime()})
         if ret[0] is False:
             if ret[1] == "conflicts":
                 continue
             if ret[1] == "zip":
                 showWarning(_("The download was corrupt. Please try again."))
             elif ret[1] == "manifest":
                 showWarning(_("Invalid add-on manifest."))
         log.append(_("Downloaded %(fname)s" % dict(fname=name)))
     self.mw.progress.finish()
     return log, errs
예제 #19
0
파일: main.py 프로젝트: Glutanimate/anki
    def _unloadCollection(self):
        if not self.col:
            return
        if self.restoringBackup:
            label = _("Closing...")
        else:
            label = _("Backing Up...")
        self.progress.start(label=label, immediate=True)
        corrupt = False
        try:
            self.maybeOptimize()
            if not devMode:
                corrupt = self.col.db.scalar("pragma integrity_check") != "ok"
        except:
            corrupt = True
        try:
            self.col.close()
        except:
            corrupt = True
        finally:
            self.col = None
        if corrupt:
            showWarning(_("Your collection file appears to be corrupt. \
This can happen when the file is copied or moved while Anki is open, or \
when the collection is stored on a network or cloud drive. If problems \
persist after restarting your computer, please open an automatic backup \
from the profile screen."))
        if not corrupt and not self.restoringBackup:
            self.backup()

        self.progress.finish()
예제 #20
0
파일: addons.py 프로젝트: jdennis/anki
    def install(self, sid, data, fname):
        try:
            z = ZipFile(io.BytesIO(data))
        except zipfile.BadZipfile:
            showWarning(_("The download was corrupt. Please try again."))
            return

        name = os.path.splitext(fname)[0]

        # previously installed?
        meta = self.addonMeta(sid)
        base = self.addonsFolder(sid)
        if os.path.exists(base):
            self.deleteAddon(sid)

        # extract
        os.mkdir(base)
        for n in z.namelist():
            if n.endswith("/"):
                # folder; ignore
                continue
            # write
            z.extract(n, base)

        # update metadata
        meta['name'] = name
        meta['mod'] = intTime()
        self.writeAddonMeta(sid, meta)
예제 #21
0
파일: addons.py 프로젝트: bbugyi200/anki
    def install(self, sid, data, fname):
        try:
            z = ZipFile(io.BytesIO(data))
        except zipfile.BadZipfile:
            showWarning(_("The download was corrupt. Please try again."))
            return

        name = os.path.splitext(fname)[0]

        # previously installed?
        meta = self.addonMeta(sid)
        base = self.addonsFolder(sid)
        if os.path.exists(base):
            self.backupUserFiles(sid)
            self.deleteAddon(sid)

        os.mkdir(base)
        self.restoreUserFiles(sid)

        # extract
        for n in z.namelist():
            if n.endswith("/"):
                # folder; ignore
                continue

            path = os.path.join(base, n)
            # skip existing user files
            if os.path.exists(path) and n.startswith("user_files/"):
                continue
            z.extract(n, base)

        # update metadata
        meta['name'] = name
        meta['mod'] = intTime()
        self.writeAddonMeta(sid, meta)
예제 #22
0
파일: __init__.py 프로젝트: dae/ankiplugins
def identifyNotes(card_ids):

    mw.progress.start(label="Reset Creation Times: collecting notes...", max=len(card_ids))
    last_nid = ""
    nids_ordered = []
    nids_lookup = {}
    
    # debug
    # showInfo(("Called identifyNotes with %s cards") % len(card_ids))
    
    # Loop through the selected cards, detecting unique notes and saving the
    # note IDs for driving the DB update.
    card_cnt = 0
    for card_cnt, card_id in enumerate(card_ids):
        
        # debug
        # showInfo(("Loop: Processing card id %s") % card_id)
        
        mw.progress.update(label=("Reset Creation Times: collecting note for card %s") % card_id,
                            value=card_cnt)

        # Retrieve the selected card to get the note ID.
        card = mw.col.getCard(card_id)
        
        # debug
        #showInfo(("retrieved card_id %s with note_id %s") % (card_id, card.nid))
        
        # We expect sibling cards (of a note) to be grouped together. When a new
        # note is encountered, save it for later processing.
        if card.nid != last_nid:
            
            # I don't think this could ever happen:
            # This is a precaution that a note's sibling cards are grouped 
            # together. If it were possible for them to be sorted in the browser
            # in a way that they wouldn't be contiguous, this would cause the
            # underlying note (creation time) to be processed twice in a way the
            # user didn't intend. Anki's data model makes this logically
            # possible, but the browser may prevent it. This test is a way to be
            # absolutely certain.
            if card.nid in nids_lookup:
                showWarning("A note found out of order. Your cards appear to be sorted in a way that siblings are not contiguous. It is not possible to reset the create time this way. Please report this to the addon discussion forum.")
            
            # Add the nid to the end of an array which will be used to drive the
            # DB update. This maintains note ids in the same order which the
            # cards appear in the browser.
            nids_ordered.append(card.nid)
            
            # Add the nid to a dictionary so we can easily reference it (to see
            # if a nid was previously encountered. I.e., whether sibling cards
            # weren't grouped together in the browser.).
            nids_lookup.update({card.nid:1})
            
            # Save the new nid value so we can skip sibling cards and detect
            # when a card belonging to a different note is encountered.
            last_nid = card.nid
    
    mw.progress.finish()
    
    return card_cnt + 1, nids_ordered
예제 #23
0
파일: errors.py 프로젝트: intact/anki
    def onTimeout(self):
        error = cgi.escape(self.pool)
        self.pool = ""
        self.mw.progress.clear()
        if "abortSchemaMod" in error:
            return
        if "Pyaudio not" in error:
            return showWarning(_("Please install PyAudio"))
        if "install mplayer" in error:
            return showWarning(_("Please install mplayer"))
        if "no default output" in error:
            return showWarning(
                _("Please connect a microphone, and ensure " "other programs are not using the audio device.")
            )
        if "invalidTempFolder" in error:
            return showWarning(self.tempFolderMsg())
        if "disk I/O error" in error:
            return showWarning(
                _(
                    """\
An error occurred while accessing the database.

Possible causes:

- Antivirus, firewall, backup, or synchronization software may be \
  interfering with Anki. Try disabling such software and see if the \
  problem goes away.
- Your disk may be full.
- The Documents/Anki folder may be on a network drive.
- Files in the Documents/Anki folder may not be writeable.
- Your hard disk may have errors.

It's a good idea to run Tools>Check Database to ensure your collection \
is not corrupt.
"""
                )
            )
        stdText = _(
            """\
An error occurred. It may have been caused by a harmless bug, <br>
or your deck may have a problem.
<p>To confirm it's not a problem with your deck, please run
<b>Tools &gt; Check Database</b>.
<p>If that doesn't fix the problem, please copy the following<br>
into a bug report:"""
        )
        pluginText = _(
            """\
An error occurred in an add-on.<br>
Please post on the add-on forum:<br>%s<br>"""
        )
        pluginText %= "https://anki.tenderapp.com/discussions/add-ons"
        if "addon" in error:
            txt = pluginText
        else:
            txt = stdText
        # show dialog
        txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
        showText(txt, type="html")
예제 #24
0
파일: editor.py 프로젝트: AidanJones/anki
 def onRecSound(self):
     try:
         file = getAudio(self.widget)
     except Exception, e:
         showWarning(_(
             "Couldn't record audio. Have you installed lame and sox?") +
                     "\n\n" + unicode(e))
         return
예제 #25
0
파일: main.py 프로젝트: jdennis/anki
 def _checkForUnclosedWidgets(self):
     for w in self.app.topLevelWidgets():
         if w.isVisible():
             # windows with this property are safe to close immediately
             if getattr(w, "silentlyClose"):
                 w.close()
             else:
                 showWarning(f"Window should have been closed: {w}")
예제 #26
0
파일: addons.py 프로젝트: Glutanimate/anki
 def onViewPage(self):
     addon = self.onlyOneSelected()
     if not addon:
         return
     if re.match(r"^\d+$", addon):
         openLink(aqt.appShared + "info/{}".format(addon))
     else:
         showWarning(_("Add-on was not downloaded from AnkiWeb."))
예제 #27
0
파일: main.py 프로젝트: samba6/ankiqt
 def profileNameOk(self, str):
     from anki.utils import invalidFilename, invalidFilenameChars
     if invalidFilename(str):
         showWarning(
             _("A profile name cannot contain these characters: %s") %
             " ".join(invalidFilenameChars))
         return
     return True
예제 #28
0
파일: editor.py 프로젝트: hans/anki
 def onRecSound(self):
     try:
         file = getAudio(self.widget)
     except Exception as e:
         showWarning(_(
             "Couldn't record audio. Have you installed lame and sox?") +
                     "\n\n" + repr(str(e)))
         return
     self.addMedia(file)
예제 #29
0
파일: __init__.py 프로젝트: dae/ankiplugins
def onResetTimes(browser):

    # Make sure user selected something.
    if not browser.form.tableView.selectionModel().hasSelection():
        showWarning("Please select at least one card to reset creation date.", parent=browser)
        return
 
    # Preprocess cards, collecting note IDs.
    (card_cnt, nids) = identifyNotes(browser.selectedCards())
    
    # debug
    #showInfo(("Processed %s cards leading to %s notes") % (card_cnt, len(nids)))
    
    # Prompt for date.
    todaystr = time.strftime('%Y/%m/%d', time.localtime())
    (s, ret) = getText("Enter a date as YYYY/MM/DD to set as the creation time, or 'today' for current date (%s):" % todaystr, parent=browser)

    if (not s) or (not ret):
        return
    
    # Generate a random MM:HH:SS. This will help prevent the same timestamp from
    # being used if this addon is executed multiple times with the same date.
    random_time = ("%s:%s:%s") % (random.randint(0, 23), random.randint(0, 59), random.randint(0, 59))

    # Don't want random? Uncomment the following line and specify any time you 
    # want in the format HH:MM:SS where HH is 00-24:
    #random_time = "15:01:01"

    
    if s == 'today':
        desttime = time.mktime(time.strptime(("%s %s") % (todaystr, random_time), '%Y/%m/%d %H:%M:%S'))
    else:
        try:
            desttime = time.mktime(time.strptime(("%s %s") % (s, random_time), '%Y/%m/%d %H:%M:%S'))
        except ValueError:
            showWarning("Sorry, I didn't understand that date.  Please enter 'today' or a date in YYYY/MM/DD format", parent=browser)
            return
   
    # This mimics anki/utils.py timestampID function (which calls intTime for
    # seconds since epoch and multiplies those seconds by 1000).
    desttime = desttime * 1000
    
    # debug
    # showInfo(("desttime %s") % desttime)

    # Force a full sync if collection isn't already marked for one. This is
    # apparently because we are changing the key column of the table.
    # (Per Damien on 2013/01/07: http://groups.google.com/group/anki-users/msg/3c8910e10f6fd0ac?hl=en )
    mw.col.modSchema(check=True)
    
    # Do it.
    resetCreationTimes(nids, desttime)
        
    # Done.
    mw.reset()
    tooltip(ngettext("Creation time reset for %d note.", "Creation time reset for %d notes.", len(nids)) % len(nids))
예제 #30
0
파일: fields.py 프로젝트: exic/ankiqt
 def _uniqueName(self, prompt, ignoreOrd=None, old=""):
     txt = getOnlyText(prompt, default=old)
     if not txt:
         return
     for f in self.model['flds']:
         if ignoreOrd is not None and f['ord'] == ignoreOrd:
             continue
         if f['name'] == txt:
             showWarning(_("That field name is already used."))
             return
     return txt
예제 #31
0
파일: main.py 프로젝트: amboss-mededu/anki
    def _openBackup(self, path):
        try:
            # move the existing collection to the trash, as it may not open
            self.pm.trashCollection()
        except:
            showWarning(
                _(
                    "Unable to move existing file to trash - please try restarting your computer."
                )
            )
            return

        self.pendingImport = path
        self.restoringBackup = True

        showInfo(
            _(
                """\
Automatic syncing and backups have been disabled while restoring. To enable them again, \
close the profile or restart Anki."""
            )
        )

        self.onOpenProfile()
예제 #32
0
파일: errors.py 프로젝트: shaunren/anki
    def onTimeout(self) -> None:
        error = html.escape(self.pool)
        self.pool = ""
        self.mw.progress.clear()
        if "abortSchemaMod" in error:
            return
        if "DeprecationWarning" in error:
            return
        if "10013" in error:
            showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS))
            return
        if "no default input" in error.lower():
            showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE))
            return
        if "invalidTempFolder" in error:
            showWarning(self.tempFolderMsg())
            return
        if "Beautiful Soup is not an HTTP client" in error:
            return
        if "database or disk is full" in error or "Errno 28" in error:
            showWarning(tr(TR.QT_MISC_YOUR_COMPUTERS_STORAGE_MAY_BE_FULL))
            return
        if "disk I/O error" in error:
            showWarning(markdown(tr(TR.ERRORS_ACCESSING_DB)))
            return

        if self.mw.addonManager.dirty:
            txt = markdown(tr(TR.ERRORS_ADDONS_ACTIVE_POPUP))
            error = f"{supportText() + self._addonText(error)}\n{error}"
        else:
            txt = markdown(tr(TR.ERRORS_STANDARD_POPUP))
            error = f"{supportText()}\n{error}"

        # show dialog
        txt = f"{txt}<div style='white-space: pre-wrap'>{error}</div>"
        showText(txt, type="html", copyBtn=True)
예제 #33
0
    def load_Group(self):
        config = mw.addonManager.getConfig(__name__)
        _translate = QtCore.QCoreApplication.translate
        url = 'https://ankileaderboard.pythonanywhere.com/groups/'
        try:
            Group_List = requests.get(url, timeout=20).json()
        except:
            Group_List = []
            showWarning(
                "Timeout error [load_Group] - No internet connection, or server response took too long.",
                title="Leaderboard error")

        # item 0 is set by pyuic from the .ui file
        for i in range(1, len(Group_List) + 1):
            self.dialog.subject.addItem("")
            self.dialog.manageGroup.addItem("")

        index = 1
        for i in Group_List:
            self.dialog.subject.setItemText(index, _translate("Dialog", i))
            self.dialog.manageGroup.setItemText(index, _translate("Dialog", i))
            index += 1

        self.dialog.subject.setCurrentText(config["subject"])
예제 #34
0
파일: deckconf.py 프로젝트: lovac42/CCBC
    def updateList(self, conf, key, w, minSize=1):
        items = str(w.text()).split(" ")
        ret = []
        for i in items:
            if not i:
                continue
            #ADDON: Small potatoes
            if i.endswith('d'):
                i = int(float(i[:-1])) * 1440

            try:
                i = float(i)
                assert i > 0
                if i == int(i):
                    i = int(i)
                ret.append(i)
            except:
                # invalid, don't update
                showWarning(_("Steps must be numbers."))
                return
        if len(ret) < minSize:
            showWarning(_("At least one step is required."))
            return
        conf[key] = ret
예제 #35
0
파일: deckconf.py 프로젝트: zhangaz1/anki
 def updateList(self,
                conf: Any,
                key: str,
                w: QLineEdit,
                minSize: int = 1) -> None:
     items = str(w.text()).split(" ")
     ret = []
     for item in items:
         if not item:
             continue
         try:
             i = float(item)
             assert i > 0
             if i == int(i):
                 i = int(i)
             ret.append(i)
         except:
             # invalid, don't update
             showWarning(_("Steps must be numbers."))
             return
     if len(ret) < minSize:
         showWarning(_("At least one step is required."))
         return
     conf[key] = ret
예제 #36
0
 def updateList(self,
                conf: Any,
                key: str,
                w: QLineEdit,
                minSize: int = 1) -> None:
     items = str(w.text()).split(" ")
     ret = []
     for item in items:
         if not item:
             continue
         try:
             i = float(item)
             assert i > 0
             if i == int(i):
                 i = int(i)
             ret.append(i)
         except:
             # invalid, don't update
             showWarning(tr(TR.SCHEDULING_STEPS_MUST_BE_NUMBERS))
             return
     if len(ret) < minSize:
         showWarning(tr(TR.SCHEDULING_AT_LEAST_ONE_STEP_IS_REQUIRED))
         return
     conf[key] = ret
예제 #37
0
 def accept(self):
     file = getSaveFile(self, _("Export"), "export", self.exporter.key,
                        self.exporter.ext)
     self.hide()
     if file:
         self.exporter.includeSched = (self.frm.includeSched.isChecked())
         self.exporter.includeMedia = (self.frm.includeMedia.isChecked())
         self.exporter.includeTags = (self.frm.includeTags.isChecked())
         if not self.frm.deck.currentIndex():
             self.exporter.did = None
         else:
             name = self.decks[self.frm.deck.currentIndex()]
             self.exporter.did = self.col.decks.id(name)
         self.mw.progress.start(immediate=True)
         try:
             f = open(file, "wb")
             f.close()
         except (OSError, IOError), e:
             showWarning(_("Couldn't save file: %s") % unicode(e))
         else:
             os.unlink(file)
             self.exporter.exportInto(file)
             tooltip(_("%d exported.") % self.exporter.count)
         finally:
예제 #38
0
파일: addcards.py 프로젝트: yzdxs/anki
    def addNote(self, note):
        note.model()['did'] = self.deckChooser.selectedId()
        ret = note.dupeOrEmpty()
        if ret == 1:
            showWarning(_("The first field is empty."),
                        help="AddItems#AddError")
            return
        if '{{cloze:' in note.model()['tmpls'][0]['qfmt']:
            if not self.mw.col.models._availClozeOrds(
                    note.model(), note.joinedFields(), False):
                if not askUser(
                        _("You have a cloze deletion note type "
                          "but have not made any cloze deletions. Proceed?")):
                    return
        cards = self.mw.col.addNote(note)
        if not cards:
            showWarning(_("""\
The input you have provided would make an empty \
question on all cards."""),
                        help="AddItems")
            return
        self.addHistory(note)
        self.mw.requireReset()
        return note
예제 #39
0
파일: clayout.py 프로젝트: godlark/Saggio
    def onRemove(self):
        if len(self.model['tmpls']) < 2:
            return showInfo(_("At least one card type is required."))
        idx = self.ord
        cards = self.mm.tmplUseCount(self.model, idx)
        cards = ngettext("%d card", "%d cards", cards) % cards
        msg = (_("Delete the '%(a)s' card type, and its %(b)s?") %
            dict(a=self.model['tmpls'][idx]['name'], b=cards))
        if not askUser(msg):
            return
        if not self.mm.remTemplate(self.model, self.cards[idx].template()):
            return showWarning(_("""\
Removing this card type would cause one or more notes to be deleted. \
Please create a new card type first."""))
        self.redraw()
예제 #40
0
    def loadCollection(self):
        try:
            return self._loadCollection()
        except Exception as e:
            showWarning(
                _("""\
Anki was unable to open your collection file. If problems persist after \
restarting your computer, please use the Open Backup button in the profile \
manager.

Debug info:
""") + traceback.format_exc())
            # clean up open collection if possible
            if self.col:
                try:
                    self.col.close(save=False)
                except:
                    pass
                self.col = None

            # return to profile manager
            self.hide()
            self.showProfileManager()
            return False
예제 #41
0
    def onRemProfile(self):
        profs = self.pm.profiles()
        if len(profs) < 2:
            return showWarning(_("There must be at least one profile."))
        # password correct?
        if not self.openProfile():
            return
        # sure?
        if not askUser(
                _("""\
All cards, notes, and media for this profile will be deleted. \
Are you sure?""")):
            return
        self.pm.remove(self.pm.name)
        self.refreshProfilesList()
예제 #42
0
파일: main.py 프로젝트: amboss-mededu/anki
    def clockIsOff(self, diff):
        diffText = ngettext("%s second", "%s seconds", diff) % diff
        warn = (
            _(
                """\
In order to ensure your collection works correctly when moved between \
devices, Anki requires your computer's internal clock to be set correctly. \
The internal clock can be wrong even if your system is showing the correct \
local time.

Please go to the time settings on your computer and check the following:

- AM/PM
- Clock drift
- Day, month and year
- Timezone
- Daylight savings

Difference to correct time: %s."""
            )
            % diffText
        )
        showWarning(warn)
        self.app.closeAllWindows()
예제 #43
0
    def onDelete(self):
        if len(self.model["flds"]) < 2:
            return showWarning(tr(TR.FIELDS_NOTES_REQUIRE_AT_LEAST_ONE_FIELD))
        count = self.mm.useCount(self.model)
        c = tr(TR.BROWSING_NOTE_COUNT, count=count)
        if not askUser(tr(TR.FIELDS_DELETE_FIELD_FROM, val=c)):
            return
        if not self.change_tracker.mark_schema():
            return
        f = self.model["flds"][self.form.fieldList.currentRow()]
        self.mm.remove_field(self.model, f)
        gui_hooks.fields_did_delete_field(self, f)

        self.fillFields()
        self.form.fieldList.setCurrentRow(0)
예제 #44
0
파일: main.py 프로젝트: pgoonghang/anki
    def onRemProfile(self):
        profs = self.pm.profiles()
        if len(profs) < 2:
            return showWarning(_("There must be at least one profile."))
        # sure?
        if not askUser(
                _("""\
All cards, notes, and media for this profile will be deleted. \
Are you sure?"""),
                msgfunc=QMessageBox.warning,
                defaultno=True,
        ):
            return
        self.pm.remove(self.pm.name)
        self.refreshProfilesList()
예제 #45
0
    def remoteLangs(self, silent=False):
        self.mw.progress.start(immediate=True)
        try:
            langs = []
            for entry in self._getRemoteDirectoryListing():
                filename = entry["name"]
                info = self._parseFilename(filename)
                if info is None:
                    continue
                filename, code, version = info
                verbose = self._langName(code)
                langs.append(Language(verbose, code, version, filename))
        except IOError as e:
            if not silent:
                showWarning((_("Please check your internet connection.") +
                             "\n\n" + str(e)),
                            textFormat="plain")
            return
        finally:
            self.mw.progress.finish()

        mapped = OrderedDict((lang.code, lang) for lang in sorted(langs))

        return mapped
예제 #46
0
def get_data(editor):
    ""

    ""

    # get word from current field
    word = stripHTMLMedia(editor.note.fields[editor.currentField])

    clean_word = _normalize_word(word)

    audio_file = save_audio(clean_word)
    if (audio_file == None):
        showWarning(
            'Vocabolaudio: no information found for the word: {}'.format(word))
        return

    editor.addMedia(audio_file)

    for field in editor.note.keys():
        if field == 'Audio' and audio_file != None:
            editor.note[field] = str('[sound:{}.{}]'.format(clean_word, 'mp3'))
            editor.note.flush()

    mw.reset()
예제 #47
0
    def accept(self):
        "On close, create notes from the contents of the poem editor."
        title = self.form.titleBox.text().strip()

        if not title:
            showWarning("You must enter a title for this poem.")
            return
        if self.mw.col.findNotes(f'"note:{models.LpcgOne.name}" "Title:{title}"'):  # pylint: disable=no-member
            showWarning("You already have a poem by that title in your "
                        "database. Please check to see if you've already "
                        "added it, or use a different name.")
            return
        if not self.form.textBox.toPlainText().strip():
            showWarning("There's nothing to generate cards from! "
                        "Please type a poem in the box, or use the "
                        '"Open File" button to import a text file.')
            return

        tags = self.mw.col.tags.split(self.form.tagsBox.text())
        text = cleanse_text(self.form.textBox.toPlainText().strip(),
                            self.mw.addonManager.getConfig(__name__))
        context_lines = self.form.contextLinesSpin.value()
        recite_lines = self.form.reciteLinesSpin.value()
        group_lines = self.form.groupLinesSpin.value()
        did = self.deckChooser.selectedId()

        try:
            notes_generated = add_notes(self.mw.col, Note, title, tags, text, did,
                                        context_lines, group_lines, recite_lines)
        except KeyError as e:
            showWarning(
                "The field {field} was not found on the {name} note type"
                " in your collection. If you don't have any LPCG notes"
                " yet, you can delete the note type in Tools -> Manage"
                " Note Types and restart Anki to fix this problem."
                " Otherwise, please add the field back to the note type. "
                .format(field=str(e), name=models.LpcgOne.name))  # pylint: disable=no-member
            return

        if notes_generated:
            super(LPCGDialog, self).accept()
            self.mw.reset()
            tooltip("%i notes added." % notes_generated)
예제 #48
0
    def onTimeout(self) -> None:
        error = html.escape(self.pool)
        self.pool = ""
        self.mw.progress.clear()
        if "AbortSchemaModification" in error:
            return
        if "DeprecationWarning" in error:
            return
        if "10013" in error:
            showWarning(tr.qt_misc_your_firewall_or_antivirus_program_is())
            return
        if "invalidTempFolder" in error:
            showWarning(self.tempFolderMsg())
            return
        if "Beautiful Soup is not an HTTP client" in error:
            return
        if "database or disk is full" in error or "Errno 28" in error:
            showWarning(tr.qt_misc_your_computers_storage_may_be_full())
            return
        if "disk I/O error" in error:
            showWarning(markdown(tr.errors_accessing_db()))
            return

        must_close = False
        if "PanicException" in error:
            must_close = True
            txt = markdown(
                "**A fatal error occurred, and Anki must close. Please report this message on the forums.**"
            )
            error = f"{supportText() + self._addonText(error)}\n{error}"
        elif self.mw.addonManager.dirty:
            txt = markdown(tr.errors_addons_active_popup())
            error = f"{supportText() + self._addonText(error)}\n{error}"
        else:
            txt = markdown(tr.errors_standard_popup())
            error = f"{supportText()}\n{error}"

        # show dialog
        txt = f"{txt}<div style='white-space: pre-wrap'>{error}</div>"
        showText(txt, type="html", copyBtn=True)
        if must_close:
            sys.exit(1)
예제 #49
0
def onRemove(self):
    """ Remove the current template, except if it would leave a note without card. Ask user for confirmation"""
    # only difference: remove current index from newTemplatesData.
    if len(self.model['tmpls']) < 2:
        return showInfo(_("At least one card type is required."))
    idx = self.ord
    cards = self.mm.tmplUseCount(self.model, idx)
    cards = ngettext("%d card", "%d cards", cards) % cards
    msg = (_("Delete the '%(a)s' card type, and its %(b)s?") %
        dict(a=self.model['tmpls'][idx]['name'], b=cards))
    if not askUser(msg):
        return
    if not self.mm.remTemplate(self.model, self.cards[idx].template()):
        return showWarning(_("""\
Removing this card type would cause one or more notes to be deleted. \
Please create a new card type first."""))

    del self.newTemplatesData[idx] # Only new line
    self.redraw()
예제 #50
0
    def create_account(self):
        username = self.dialog.create_username.text()
        config = mw.addonManager.getConfig(__name__)
        url = 'https://ankileaderboard.pythonanywhere.com/allusers/'
        try:
            username_list = requests.get(url, timeout=20).json()
        except:
            showWarning(
                "Timeout error [create_account] - No internet connection, or server response took too long.",
                title="Leaderboard error")

        if username in username_list:
            tooltip("Username already taken")
        else:
            url = 'https://ankileaderboard.pythonanywhere.com/sync/'

            streak, cards, time, cards_past_30_days, retention, league_reviews, league_time, league_retention = Stats(
                self.season_start, self.season_end)
            config5 = config['subject'].replace(" ", "")
            config6 = config['country'].replace(" ", "")

            data = {
                'Username': username,
                "Streak": streak,
                "Cards": cards,
                "Time": time,
                "Sync_Date": datetime.now(),
                "Month": cards_past_30_days,
                "Country": config["country"],
                "Retention": retention,
                "league_reviews": league_reviews,
                "league_time": league_time,
                "league_retention": league_retention,
                "Version": config["version"]
            }

            try:
                x = requests.post(url, data=data)
                if x.text == "Done!":
                    tooltip("Successfully created account.")
                else:
                    showWarning(str(x.text))
                write_config("username", username)
                self.dialog.create_username.setText("")
                self.update_login_info(username)
            except:
                showWarning(
                    "Timeout error [create_account] - No internet connection, or server response took too long.",
                    title="Leaderboard error")
예제 #51
0
    def manage_group(self):
        config = mw.addonManager.getConfig(__name__)
        group = self.dialog.manageGroup.currentText()
        oldPwd = self.dialog.oldPwd.text()
        newPwd = self.dialog.manage_newPwd.text()
        rPwd = self.dialog.manage_newRepeat.text()
        addAdmin = self.dialog.newAdmin.text()

        if newPwd != rPwd:
            showWarning("Passwords are not the same.")
            self.dialog.manage_newPwd.clear()
            self.dialog.manage_newRepeat.clear()
            return
        else:
            if oldPwd == "":
                oldPwd = None
            else:
                oldPwd = hashlib.sha1(
                    oldPwd.encode('utf-8')).hexdigest().upper()

            if newPwd == "":
                newPwd = oldPwd
            else:
                newPwd = hashlib.sha1(
                    newPwd.encode('utf-8')).hexdigest().upper()

        url = 'https://ankileaderboard.pythonanywhere.com/manageGroup/'
        data = {
            'group': group,
            "user": config["username"],
            "token": config["token"],
            "oldPwd": oldPwd,
            "newPwd": newPwd,
            "addAdmin": addAdmin
        }

        try:
            x = requests.post(url, data=data, timeout=20)
            if x.text == "Done!":
                tooltip(f"{group} was updated successfully.")
                write_config("group_pwd",
                             newPwd) if oldPwd != newPwd else write_config(
                                 "group_pwd", oldPwd)
            else:
                showWarning(str(x.text))
        except:
            showWarning(
                "Timeout error [manage_group] - No internet connection, or server response took too long.",
                title="Leaderboard error")
예제 #52
0
 def _delete(self, did):
     if str(did) == '1':
         return showWarning(_("The default deck can't be deleted."))
     self.mw.checkpoint(_("Delete Deck"))
     deck = self.mw.col.decks.get(did)
     if not deck['dyn']:
         dids = [did] + [r[1] for r in self.mw.col.decks.children(did)]
         cnt = self.mw.col.db.scalar(
             "select count() from cards where did in {0} or "
             "odid in {0}".format(ids2str(dids)))
         if cnt:
             extra = _(" It has %d cards.") % cnt
         else:
             extra = None
     if deck['dyn'] or not extra or askUser(
         (_("Are you sure you wish to delete %s?") % deck['name']) + extra):
         self.mw.progress.start(immediate=True)
         self.mw.col.decks.rem(did, True)
         self.mw.progress.finish()
         self.show()
예제 #53
0
def queueExternal(path):
    global p, _player

    if mw.state == "review" and mw.reviewer.card != None and (
            mw.reviewer.card.model()["name"] == "movies2anki (add-on)"
            or mw.reviewer.card.model()["name"].startswith(
                "movies2anki - subs2srs")):
        if mw.reviewer.state == "answer" and path.endswith(".mp4"):
            return

        try:
            clearExternalQueue()
            playVideoClip(path)
        except OSError:
            return showWarning(
                r"""<p>Please install <a href='https://mpv.io'>mpv</a>.</p>
                On Windows download mpv and either update PATH environment variable or put mpv.exe in Anki installation folder (C:\Program Files\Anki).""",
                parent=mw)
    else:
        _player(path)
예제 #54
0
파일: profiles.py 프로젝트: zhumaohong/anki
    def rename(self, name):
        oldName = self.name
        oldFolder = self.profileFolder()
        self.name = name
        newFolder = self.profileFolder(create=False)
        if os.path.exists(newFolder):
            if (oldFolder != newFolder) and (oldFolder.lower() == newFolder.lower()):
                # OS is telling us the folder exists because it does not take
                # case into account; use a temporary folder location
                midFolder = "".join([oldFolder, "-temp"])
                if not os.path.exists(midFolder):
                    os.rename(oldFolder, midFolder)
                    oldFolder = midFolder
                else:
                    showWarning(
                        _("Please remove the folder %s and try again.") % midFolder
                    )
                    self.name = oldName
                    return
            else:
                showWarning(_("Folder already exists."))
                self.name = oldName
                return

        # update name
        self.db.execute("update profiles set name = ? where name = ?", name, oldName)
        # rename folder
        try:
            os.rename(oldFolder, newFolder)
        except Exception as e:
            self.db.rollback()
            if "WinError 5" in str(e):
                showWarning(
                    _(
                        """\
Anki could not rename your profile because it could not rename the profile \
folder on disk. Please ensure you have permission to write to Documents/Anki \
and no other programs are accessing your profile folders, then try again."""
                    )
                )
            else:
                raise
        except:
            self.db.rollback()
            raise
        else:
            self.db.commit()
예제 #55
0
    def _flatten(self, did):
        deck = self.mw.col.decks.get(did)
        if deck['dyn']:
            return showWarning(_("You can't flatten a dynamic deck"))
        self.mw.checkpoint(_("Flatten deck"))

        deck = self.mw.col.decks.get(did)
        dids = [r[1] for r in self.mw.col.decks.children(did)]
        cnt = self.mw.col.db.scalar(
            "select count() from cards where did in {0} or "
            "odid in {0}".format(ids2str(dids)))
        if cnt:
            extra = _(" Children decks have %d cards in total.") % cnt
        else:
            extra = None
        if not extra or askUser(
            (_("Are you sure you wish to flatten the deck %s?") %
             deck['name']) + extra):
            self.mw.progress.start(immediate=True)
            self.mw.col.decks.flatten(did)
            self.mw.progress.finish()
            self.show()
예제 #56
0
def _rename(self, did, newName=None):
    self.mw.checkpoint(_("Rename Deck"))
    deck = self.mw.col.decks.get(did)
    oldName = deck['name']
    if newName is None:
        newName = getOnlyText(_("New deck name:"), default=oldName)
        newName = newName.replace('"', "")
    if not newName or newName == oldName:
        return
    try:
        if newName in self.mw.col.decks.allNames():
            merge = askUser(
                _("The deck %s already exists. Do you want to merge %s in it ?"
                  ) % (newName, oldName))
            if merge:
                self.mw.col.decks.rename(deck, newName)
        else:
            self.mw.col.decks.rename(deck, newName)

    except DeckRenameError as e:
        return showWarning(e.description)
    self.show()
예제 #57
0
    def onTimeout(self):
        error = html.escape(self.pool)
        self.pool = ""
        self.mw.progress.clear()
        if "abortSchemaMod" in error:
            return
        if "10013" in error:
            return showWarning(
                _("Your firewall or antivirus program is preventing Anki from creating a connection to itself. Please add an exception for Anki."
                  ))
        if "install mplayer" in error:
            return showWarning(
                _("Sound and video on cards will not function until mpv or mplayer is installed."
                  ))
        if "no default input" in error.lower():
            return showWarning(
                _("Please connect a microphone, and ensure "
                  "other programs are not using the audio device."))
        if "invalidTempFolder" in error:
            return showWarning(self.tempFolderMsg())
        if "Beautiful Soup is not an HTTP client" in error:
            return
        if "database or disk is full" in error or "Errno 28" in error:
            return showWarning(
                _("Your computer's storage may be full. Please delete some unneeded files, then try again."
                  ))
        if "disk I/O error" in error:
            showWarning(markdown(tr(FString.ERRORS_ACCESSING_DB)))
            return

        if self.mw.addonManager.dirty:
            txt = markdown(tr(FString.ERRORS_ADDONS_ACTIVE_POPUP))
            error = supportText() + self._addonText(error) + "\n" + error
        else:
            txt = markdown(tr(FString.ERRORS_STANDARD_POPUP))
            error = supportText() + "\n" + error

        # show dialog
        txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
        showText(txt, type="html", copyBtn=True)
예제 #58
0
    def _retrieveURL(self, url):
        "Download file into media folder and return local filename or None."
        # urllib doesn't understand percent-escaped utf8, but requires things like
        # '#' to be escaped.
        url = urllib.parse.unquote(url)
        if url.lower().startswith("file://"):
            url = url.replace("%", "%25")
            url = url.replace("#", "%23")
            local = True
        else:
            local = False
        # fetch it into a temporary folder
        self.mw.progress.start(immediate=not local, parent=self.parentWindow)
        ct = None
        try:
            if local:
                req = urllib.request.Request(
                    url, None,
                    {"User-Agent": "Mozilla/5.0 (compatible; Anki)"})
                filecontents = urllib.request.urlopen(req).read()
            else:
                reqs = HttpClient()
                reqs.timeout = 30
                r = reqs.get(url)
                if r.status_code != 200:
                    showWarning(
                        _("Unexpected response code: %s") % r.status_code)
                    return
                filecontents = r.content
                ct = r.headers.get("content-type")
        except urllib.error.URLError as e:
            showWarning(_("An error occurred while opening %s") % e)
            return
        except requests.exceptions.RequestException as e:
            showWarning(_("An error occurred while opening %s") % e)
            return
        finally:
            self.mw.progress.finish()
        # strip off any query string
        url = re.sub(r"\?.*?$", "", url)
        fname = os.path.basename(urllib.parse.unquote(url))
        if ct:
            fname = self.mw.col.media.add_extension_based_on_mime(fname, ct)

        return self.mw.col.media.write_data(fname, filecontents)
예제 #59
0
 def _uniqueName(self, prompt, ignoreOrd=None, old=""):
     txt = getOnlyText(prompt, default=old).replace('"', "").strip()
     if not txt:
         return
     if txt[0] in "#^/":
         showWarning(tr(TR.FIELDS_NAME_FIRST_LETTER_NOT_VALID))
         return
     for letter in """:{"}""":
         if letter in txt:
             showWarning(tr(TR.FIELDS_NAME_INVALID_LETTER))
             return
     for f in self.model["flds"]:
         if ignoreOrd is not None and f["ord"] == ignoreOrd:
             continue
         if f["name"] == txt:
             showWarning(tr(TR.FIELDS_THAT_FIELD_NAME_IS_ALREADY_USED))
             return
     return txt
예제 #60
0
파일: profiles.py 프로젝트: humbatoa/anki
    def rename(self, name: str) -> None:
        oldName = self.name
        oldFolder = self.profileFolder()
        self.name = name
        newFolder = self.profileFolder(create=False)
        if os.path.exists(newFolder):
            if (oldFolder != newFolder) and (oldFolder.lower()
                                             == newFolder.lower()):
                # OS is telling us the folder exists because it does not take
                # case into account; use a temporary folder location
                midFolder = "".join([oldFolder, "-temp"])
                if not os.path.exists(midFolder):
                    os.rename(oldFolder, midFolder)
                    oldFolder = midFolder
                else:
                    showWarning(
                        tr(TR.PROFILES_PLEASE_REMOVE_THE_FOLDER_AND,
                           val=midFolder))
                    self.name = oldName
                    return
            else:
                showWarning(tr(TR.PROFILES_FOLDER_ALREADY_EXISTS))
                self.name = oldName
                return

        # update name
        self.db.execute("update profiles set name = ? where name = ?", name,
                        oldName)
        # rename folder
        try:
            os.rename(oldFolder, newFolder)
        except Exception as e:
            self.db.rollback()
            if "WinError 5" in str(e):
                showWarning(tr(TR.PROFILES_ANKI_COULD_NOT_RENAME_YOUR_PROFILE))
            else:
                raise
        except:
            self.db.rollback()
            raise
        else:
            self.db.commit()