mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
implement addons
This commit is contained in:
parent
6148a28bfb
commit
08134c2462
3 changed files with 89 additions and 139 deletions
224
aqt/addons.py
224
aqt/addons.py
|
@ -10,155 +10,105 @@ from anki.hooks import runHook
|
|||
class AddonManager(object):
|
||||
|
||||
def __init__(self, mw):
|
||||
print "addons"
|
||||
return
|
||||
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)
|
||||
self.mw.connect(f.actionOpenPluginFolder, s, self.onOpenAddonFolder)
|
||||
self.mw.connect(f.actionEnableAllPlugins, s, self.onEnableAllAddons)
|
||||
self.mw.connect(f.actionDisableAllPlugins, s, self.onDisableAllAddons)
|
||||
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.rebuildPluginsMenu()
|
||||
# run the obsolete init hook
|
||||
try:
|
||||
runHook('init')
|
||||
except:
|
||||
showWarning(
|
||||
_("Broken plugin:\n\n%s") %
|
||||
unicode(traceback.format_exc(), "utf-8", "replace"))
|
||||
self.clearAddonCache()
|
||||
sys.path.insert(0, self.addonsFolder())
|
||||
self.loadAddons()
|
||||
|
||||
def pluginsFolder(self):
|
||||
dir = self.mw.config.confDir
|
||||
def loadAddons(self):
|
||||
on, off = self.files()
|
||||
for file in on:
|
||||
try:
|
||||
__import__(file.replace(".py", ""))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.rebuildAddonsMenu()
|
||||
|
||||
# Menus
|
||||
######################################################################
|
||||
|
||||
def rebuildAddonsMenu(self):
|
||||
if getattr(self, "addonActions", None) is None:
|
||||
self.addonActions = []
|
||||
for action in self.addonActions:
|
||||
self.mw.form.menuStartup.removeAction(action)
|
||||
self.addonActions = []
|
||||
on, off = self.files()
|
||||
def addObjs(l, enabled):
|
||||
l.sort()
|
||||
for file in l:
|
||||
p = re.sub("\.py(\.off)?", "", file)
|
||||
a = QAction(p, self.mw)
|
||||
a.setCheckable(True)
|
||||
a.setChecked(enabled)
|
||||
self.mw.connect(a, SIGNAL("triggered()"),
|
||||
lambda f=file: self.toggleAddon(f))
|
||||
self.mw.form.menuStartup.addAction(a)
|
||||
self.addonActions.append(a)
|
||||
addObjs(on, True)
|
||||
addObjs(off, False)
|
||||
|
||||
def onOpenAddonFolder(self, path=None):
|
||||
if path is None:
|
||||
path = self.addonsFolder()
|
||||
openFolder(path)
|
||||
|
||||
# Enabled/disabled list
|
||||
######################################################################
|
||||
|
||||
def files(self):
|
||||
on = []
|
||||
off = []
|
||||
for f in os.listdir(self.addonsFolder()):
|
||||
if not f.endswith(".py"):
|
||||
continue
|
||||
if f in self.mw.pm.meta['disabledAddons']:
|
||||
off.append(f)
|
||||
else:
|
||||
on.append(f)
|
||||
return on, off
|
||||
|
||||
def onEnableAllAddons(self):
|
||||
self.mw.pm.meta['disabledAddons'] = []
|
||||
self.mw.pm.save()
|
||||
self.rebuildAddonsMenu()
|
||||
|
||||
def onDisableAllAddons(self):
|
||||
on, off = self.files()
|
||||
self.mw.pm.meta['disabledAddons'] = on + off
|
||||
self.rebuildAddonsMenu()
|
||||
|
||||
def toggleAddon(self, file):
|
||||
if file in self.mw.pm.meta['disabledAddons']:
|
||||
self.mw.pm.meta['disabledAddons'].remove(file)
|
||||
else:
|
||||
self.mw.pm.meta['disabledAddons'].append(file)
|
||||
self.mw.pm.save()
|
||||
self.rebuildAddonsMenu()
|
||||
|
||||
# Tools
|
||||
######################################################################
|
||||
|
||||
def addonsFolder(self):
|
||||
dir = self.mw.pm.addonFolder()
|
||||
if isWin:
|
||||
dir = dir.encode(sys.getfilesystemencoding())
|
||||
return os.path.join(dir, "addons")
|
||||
return dir
|
||||
|
||||
def clearPluginCache(self):
|
||||
def clearAddonCache(self):
|
||||
"Clear .pyc files which may cause crashes if Python version updated."
|
||||
dir = self.pluginsFolder()
|
||||
dir = self.addonsFolder()
|
||||
for curdir, dirs, files in os.walk(dir):
|
||||
for f in files:
|
||||
if not f.endswith(".pyc"):
|
||||
continue
|
||||
os.unlink(os.path.join(curdir, f))
|
||||
|
||||
def disableObsoletePlugins(self):
|
||||
dir = self.pluginsFolder()
|
||||
native = _(
|
||||
"The %s plugin has been disabled, as Anki supports "+
|
||||
"this natively now.")
|
||||
plugins = [
|
||||
("Custom Media Directory.py",
|
||||
(native % "custom media folder") + _(""" \
|
||||
Please visit Settings>Preferences.""")),
|
||||
("Regenerate Reading Field.py", _("""\
|
||||
The regenerate reading field plugin has been disabled, as the Japanese \
|
||||
support plugin supports this now. Please download the latest version.""")),
|
||||
("Sync LaTeX with iPhone client.py",
|
||||
native % "sync LaTeX"),
|
||||
("Incremental Reading.py",
|
||||
_("""The incremental reading plugin has been disabled because \
|
||||
it needs updates.""")),
|
||||
("Learn Mode.py", _("""\
|
||||
The learn mode plugin has been disabled because it needs to be rewritten \
|
||||
to work with this version of Anki."""))
|
||||
]
|
||||
for p in plugins:
|
||||
path = os.path.join(dir, p[0])
|
||||
if os.path.exists(path):
|
||||
new = path.replace(".py", ".disabled")
|
||||
if os.path.exists(new):
|
||||
os.unlink(new)
|
||||
os.rename(path, new)
|
||||
showInfo(p[1])
|
||||
|
||||
def rebuildPluginsMenu(self):
|
||||
if getattr(self, "pluginActions", None) is None:
|
||||
self.pluginActions = []
|
||||
for action in self.pluginActions:
|
||||
self.mw.form.menuStartup.removeAction(action)
|
||||
all = self.allPlugins()
|
||||
all.sort()
|
||||
for fname in all:
|
||||
enabled = fname.endswith(".py")
|
||||
p = re.sub("\.py(\.off)?", "", fname)
|
||||
if p+".py" in self.registeredPlugins:
|
||||
p = self.registeredPlugins[p+".py"]['name']
|
||||
a = QAction(p, self.mw)
|
||||
a.setCheckable(True)
|
||||
a.setChecked(enabled)
|
||||
self.mw.connect(a, SIGNAL("triggered()"),
|
||||
lambda fname=fname: self.togglePlugin(fname))
|
||||
self.mw.form.menuStartup.addAction(a)
|
||||
self.pluginActions.append(a)
|
||||
|
||||
def enabledPlugins(self):
|
||||
return [p for p in os.listdir(self.pluginsFolder())
|
||||
if p.endswith(".py")]
|
||||
|
||||
def disabledPlugins(self):
|
||||
return [p for p in os.listdir(self.pluginsFolder())
|
||||
if p.endswith(".py.off")]
|
||||
|
||||
def allPlugins(self):
|
||||
return [p for p in os.listdir(self.pluginsFolder())
|
||||
if p.endswith(".py.off") or p.endswith(".py")]
|
||||
|
||||
def onOpenPluginFolder(self, path=None):
|
||||
if path is None:
|
||||
path = self.pluginsFolder()
|
||||
openFolder(path)
|
||||
|
||||
def enablePlugin(self, p):
|
||||
pd = self.pluginsFolder()
|
||||
old = os.path.join(pd, p)
|
||||
new = os.path.join(pd, p.replace(".off", ""))
|
||||
try:
|
||||
os.unlink(new)
|
||||
except:
|
||||
pass
|
||||
os.rename(old, new)
|
||||
|
||||
def disablePlugin(self, p):
|
||||
pd = self.pluginsFolder()
|
||||
old = os.path.join(pd, p)
|
||||
new = os.path.join(pd, p.replace(".py", ".py.off"))
|
||||
try:
|
||||
os.unlink(new)
|
||||
except:
|
||||
pass
|
||||
os.rename(old, new)
|
||||
|
||||
def onEnableAllPlugins(self):
|
||||
for p in self.disabledPlugins():
|
||||
self.enablePlugin(p)
|
||||
self.rebuildPluginsMenu()
|
||||
|
||||
def onDisableAllPlugins(self):
|
||||
for p in self.enabledPlugins():
|
||||
self.disablePlugin(p)
|
||||
self.rebuildPluginsMenu()
|
||||
|
||||
def togglePlugin(self, plugin):
|
||||
if plugin.endswith(".py"):
|
||||
self.disablePlugin(plugin)
|
||||
else:
|
||||
self.enablePlugin(plugin)
|
||||
self.rebuildPluginsMenu()
|
||||
|
||||
def registerPlugin(self, name, updateId):
|
||||
def registerAddon(self, name, updateId):
|
||||
# not currently used
|
||||
return
|
||||
|
|
|
@ -58,7 +58,7 @@ Please do not file a bug report with Anki.<br>""")
|
|||
self.mw.progress.clear()
|
||||
if "abortSchemaMod" in error:
|
||||
return
|
||||
if "plugin" in error:
|
||||
if "addon" in error:
|
||||
txt = pluginText
|
||||
else:
|
||||
txt = stdText
|
||||
|
|
|
@ -23,6 +23,7 @@ metaConf = dict(
|
|||
suppressUpdate=False,
|
||||
firstRun=True,
|
||||
defaultLang=None,
|
||||
disabledAddons=[],
|
||||
)
|
||||
|
||||
profileConf = dict(
|
||||
|
@ -33,7 +34,6 @@ profileConf = dict(
|
|||
numBackups=30,
|
||||
lastOptimize=intTime(),
|
||||
lang="en",
|
||||
disabledAddons=[],
|
||||
|
||||
# editing
|
||||
fullSearch=False,
|
||||
|
|
Loading…
Reference in a new issue