split plugin handling into separate file

This commit is contained in:
Damien Elmes 2011-03-27 12:44:54 +09:00
parent e6b153df13
commit a1e5a13f98
3 changed files with 182 additions and 173 deletions

View file

@ -36,7 +36,7 @@ class AnkiQt(QMainWindow):
self.setup() self.setup()
splash.update() splash.update()
# load plugins # load plugins
self.loadPlugins() self.setupPlugins()
splash.update() splash.update()
# show main window # show main window
splash.finish(self) splash.finish(self)
@ -334,6 +334,10 @@ counts are %d %d %d
if self.appUpdated: if self.appUpdated:
self.config['version'] = aqt.appVersion self.config['version'] = aqt.appVersion
def setupPlugins(self):
import aqt.plugins
self.pluginManager = aqt.plugins.PluginManager(self)
def setupThreads(self): def setupThreads(self):
self._mainThread = QThread.currentThread() self._mainThread = QThread.currentThread()
@ -1711,9 +1715,6 @@ This deck already exists on your computer. Overwrite the local copy?"""),
self.connect(m.actionDownloadMissingMedia, s, self.onDownloadMissingMedia) self.connect(m.actionDownloadMissingMedia, s, self.onDownloadMissingMedia)
self.connect(m.actionLocalizeMedia, s, self.onLocalizeMedia) self.connect(m.actionLocalizeMedia, s, self.onLocalizeMedia)
self.connect(m.actionCram, s, self.onCram) self.connect(m.actionCram, s, self.onCram)
self.connect(m.actionOpenPluginFolder, s, self.onOpenPluginFolder)
self.connect(m.actionEnableAllPlugins, s, self.onEnableAllPlugins)
self.connect(m.actionDisableAllPlugins, s, self.onDisableAllPlugins)
self.connect(m.actionStudyOptions, s, self.onStudyOptions) self.connect(m.actionStudyOptions, s, self.onStudyOptions)
self.connect(m.actionDonate, s, self.onDonate) self.connect(m.actionDonate, s, self.onDonate)
self.connect(m.actionRecordNoiseProfile, s, self.onRecordNoiseProfile) self.connect(m.actionRecordNoiseProfile, s, self.onRecordNoiseProfile)
@ -1833,172 +1834,6 @@ This deck already exists on your computer. Overwrite the local copy?"""),
_(" Please ensure it is set correctly and then restart Anki.") _(" Please ensure it is set correctly and then restart Anki.")
) )
# Plugins
##########################################################################
def pluginsFolder(self):
dir = self.config.confDir
if sys.platform.startswith("win32"):
dir = dir.encode(sys.getfilesystemencoding())
return os.path.join(dir, "plugins")
def loadPlugins(self):
if sys.platform.startswith("win32"):
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.checkForUpdatedPlugins()
self.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"))
def clearPluginCache(self):
"Clear .pyc files which may cause crashes if Python version updated."
dir = self.pluginsFolder()
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.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)
a.setCheckable(True)
a.setChecked(enabled)
self.connect(a, SIGNAL("triggered()"),
lambda fname=fname: self.togglePlugin(fname))
self.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()
if sys.platform == "win32":
if isinstance(path, unicode):
path = path.encode(sys.getfilesystemencoding())
anki.utils.call(["explorer", path], wait=False)
else:
QDesktopServices.openUrl(QUrl("file://" + path))
def onGetPlugins(self):
QDesktopServices.openUrl(QUrl("http://ichi2.net/anki/wiki/Plugins"))
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):
return
# src = os.path.basename(inspect.getfile(inspect.currentframe(1)))
# self.registeredPlugins[src] = {'name': name,
# 'id': updateId}
def checkForUpdatedPlugins(self):
pass
# Custom styles # Custom styles
########################################################################## ##########################################################################

167
aqt/plugins.py Normal file
View file

@ -0,0 +1,167 @@
# Copyright: Damien Elmes <anki@ichi2.net>
# -*- coding: utf-8 -*-
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
import sys, os, re
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from aqt.utils import showInfo, showWarning, openFolder
from anki.hooks import runHook
class PluginManager(object):
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 sys.platform.startswith("win32"):
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"))
def pluginsFolder(self):
dir = self.mw.config.confDir
if sys.platform.startswith("win32"):
dir = dir.encode(sys.getfilesystemencoding())
return os.path.join(dir, "plugins")
def clearPluginCache(self):
"Clear .pyc files which may cause crashes if Python version updated."
dir = self.pluginsFolder()
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 onGetPlugins(self):
QDesktopServices.openUrl(QUrl("http://ichi2.net/anki/wiki/Plugins"))
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):
return

View file

@ -3,11 +3,10 @@
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from anki.sound import playFromText, stripSounds
import re, os, sys, urllib, time import re, os, sys, urllib, time
import aqt import aqt
from anki.sound import playFromText, stripSounds
from anki.utils import call
def openLink(link): def openLink(link):
QDesktopServices.openUrl(QUrl(link)) QDesktopServices.openUrl(QUrl(link))
@ -285,3 +284,11 @@ def getBase(deck, card):
return '<base href="%s">' % base return '<base href="%s">' % base
else: else:
return "" return ""
def openFolder(path):
if sys.platform == "win32":
if isinstance(path, unicode):
path = path.encode(sys.getfilesystemencoding())
call(["explorer", path], wait=False)
else:
QDesktopServices.openUrl(QUrl("file://" + path))