4735: Check for updates in a separate thread
svn: r22926
This commit is contained in:
parent
f9540a469f
commit
94d0a21d08
@ -31,11 +31,20 @@ General utility functions useful for the generic plugin system
|
||||
#-------------------------------------------------------------------------
|
||||
import sys
|
||||
import os
|
||||
import datetime
|
||||
if sys.version_info[0] < 3:
|
||||
from StringIO import StringIO
|
||||
else:
|
||||
from io import StringIO, BytesIO
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# set up logging
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
LOG = logging.getLogger(".gen.plug")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps modules
|
||||
@ -44,7 +53,10 @@ else:
|
||||
from ._pluginreg import make_environment
|
||||
from ..const import USER_PLUGINS
|
||||
from ...version import VERSION_TUPLE
|
||||
from . import BasePluginManager
|
||||
from ..utils.file import get_unicode_path_from_file_chooser
|
||||
from ..utils.configmanager import safe_eval
|
||||
from ..config import config
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.gettext
|
||||
|
||||
@ -166,6 +178,90 @@ class Zipfile(object):
|
||||
"""
|
||||
return os.path.split(name)[1]
|
||||
|
||||
def available_updates():
|
||||
whattypes = config.get('behavior.check-for-update-types')
|
||||
if sys.version_info[0] < 3:
|
||||
from urllib2 import urlopen
|
||||
else:
|
||||
from urllib.request import urlopen
|
||||
LOG.debug("Checking for updated addons...")
|
||||
langs = glocale.get_language_list()
|
||||
langs.append("en")
|
||||
# now we have a list of languages to try:
|
||||
fp = None
|
||||
for lang in langs:
|
||||
URL = ("%s/listings/addons-%s.txt" %
|
||||
(config.get("behavior.addons-url"), lang))
|
||||
LOG.debug(" trying: %s" % URL)
|
||||
try:
|
||||
fp = urlopen(URL, timeout=10) # abort after 10 seconds
|
||||
except:
|
||||
try:
|
||||
URL = ("%s/listings/addons-%s.txt" %
|
||||
(config.get("behavior.addons-url"), lang[:2]))
|
||||
fp = urlopen(URL, timeout=10)
|
||||
except Exception as err: # some error
|
||||
LOG.warn("Failed to open %s: %s" % (lang, err))
|
||||
fp = None
|
||||
if fp and fp.getcode() == 200: # ok
|
||||
break
|
||||
|
||||
pmgr = BasePluginManager.get_instance()
|
||||
addon_update_list = []
|
||||
if fp and fp.getcode() == 200:
|
||||
lines = list(fp.readlines())
|
||||
count = 0
|
||||
for line in lines:
|
||||
line = line.decode('utf-8')
|
||||
try:
|
||||
plugin_dict = safe_eval(line)
|
||||
if type(plugin_dict) != type({}):
|
||||
raise TypeError("Line with addon metadata is not "
|
||||
"a dictionary")
|
||||
except:
|
||||
LOG.warning("Skipped a line in the addon listing: " +
|
||||
str(line))
|
||||
continue
|
||||
id = plugin_dict["i"]
|
||||
plugin = pmgr.get_plugin(id)
|
||||
if plugin:
|
||||
LOG.debug("Comparing %s > %s" %
|
||||
(version_str_to_tup(plugin_dict["v"], 3),
|
||||
version_str_to_tup(plugin.version, 3)))
|
||||
if (version_str_to_tup(plugin_dict["v"], 3) >
|
||||
version_str_to_tup(plugin.version, 3)):
|
||||
LOG.debug(" Downloading '%s'..." % plugin_dict["z"])
|
||||
if "update" in whattypes:
|
||||
if (not config.get('behavior.do-not-show-previously-seen-updates') or
|
||||
plugin_dict["i"] not in config.get('behavior.previously-seen-updates')):
|
||||
addon_update_list.append((_("Updated"),
|
||||
"%s/download/%s" %
|
||||
(config.get("behavior.addons-url"),
|
||||
plugin_dict["z"]),
|
||||
plugin_dict))
|
||||
else:
|
||||
LOG.debug(" '%s' is ok" % plugin_dict["n"])
|
||||
else:
|
||||
LOG.debug(" '%s' is not installed" % plugin_dict["n"])
|
||||
if "new" in whattypes:
|
||||
if (not config.get('behavior.do-not-show-previously-seen-updates') or
|
||||
plugin_dict["i"] not in config.get('behavior.previously-seen-updates')):
|
||||
addon_update_list.append((_("New"),
|
||||
"%s/download/%s" %
|
||||
(config.get("behavior.addons-url"),
|
||||
plugin_dict["z"]),
|
||||
plugin_dict))
|
||||
config.set("behavior.last-check-for-updates",
|
||||
datetime.date.today().strftime("%Y/%m/%d"))
|
||||
count += 1
|
||||
if fp:
|
||||
fp.close()
|
||||
else:
|
||||
LOG.debug("Checking Addons Failed")
|
||||
LOG.debug("Done checking!")
|
||||
|
||||
return addon_update_list
|
||||
|
||||
def load_addon_file(path, callback=None):
|
||||
"""
|
||||
Load an addon from a particular path (from URL or file system).
|
||||
|
@ -68,6 +68,9 @@ from .managedwindow import ManagedWindow
|
||||
from .widgets import MarkupLabel, BasicLabel
|
||||
from .dialog import ErrorDialog, QuestionDialog2, OkDialog
|
||||
from .glade import Glade
|
||||
from gramps.gen.plug.utils import available_updates
|
||||
from .plug import PluginWindows
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -1308,12 +1311,39 @@ class GrampsPreferences(ConfigureDialog):
|
||||
|
||||
table.attach(checkbutton, 0, 3, current_line, current_line+1, yoptions=0)
|
||||
button = Gtk.Button(_("Check now"))
|
||||
button.connect("clicked", lambda obj: \
|
||||
self.uistate.viewmanager.check_for_updates(force=True))
|
||||
button.connect("clicked", self.check_for_updates)
|
||||
table.attach(button, 3, 4, current_line, current_line+1, yoptions=0)
|
||||
|
||||
return _('General'), table
|
||||
|
||||
def check_for_updates(self, button):
|
||||
try:
|
||||
addon_update_list = available_updates()
|
||||
except:
|
||||
OkDialog(_("Checking Addons Failed"),
|
||||
_("The addon repository appears to be unavailable. "
|
||||
"Please try again later."),
|
||||
self.window)
|
||||
return
|
||||
|
||||
if len(addon_update_list) > 0:
|
||||
try:
|
||||
PluginWindows.UpdateAddons(self.uistate, [], addon_update_list)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
else:
|
||||
check_types = config.get('behavior.check-for-update-types')
|
||||
OkDialog(_("There are no available addons of this type"),
|
||||
_("Checked for '%s'") %
|
||||
_("' and '").join([_(t) for t in check_types]),
|
||||
self.window)
|
||||
|
||||
# List of translated strings used here
|
||||
# Dead code for l10n
|
||||
_('new'), _('update')
|
||||
|
||||
self.uistate.viewmanager.do_reg_plugins(self.dbstate, self.uistate)
|
||||
|
||||
def add_famtree_panel(self, configdialog):
|
||||
table = Gtk.Table(2, 2)
|
||||
table.set_border_width(12)
|
||||
|
@ -373,6 +373,7 @@ class DisplayState(Callback):
|
||||
'filter-name-changed' : (str, UNITYPE, UNITYPE),
|
||||
'nameformat-changed' : None,
|
||||
'grampletbar-close-changed' : None,
|
||||
'update-available' : (list, ),
|
||||
}
|
||||
|
||||
#nav_type to message
|
||||
|
@ -34,6 +34,14 @@ import traceback
|
||||
import os
|
||||
import sys
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# set up logging
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
LOG = logging.getLogger(".gui.plug")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GTK modules
|
||||
@ -58,11 +66,15 @@ from ..utils import open_file_with_default_application
|
||||
from ..pluginmanager import GuiPluginManager
|
||||
from . import tool
|
||||
from ._guioptions import add_gui_options
|
||||
from ..dialog import InfoDialog
|
||||
from ..dialog import InfoDialog, OkDialog
|
||||
from ..editors import EditPerson
|
||||
from ..glade import Glade
|
||||
from ..listmodel import ListModel, NOSORT, TOGGLE
|
||||
from gramps.gen.utils.file import get_unicode_path_from_file_chooser
|
||||
from gramps.gen.const import URL_WIKISTRING, USER_HOME, WIKI_EXTRAPLUGINS_RAWDATA
|
||||
from gramps.gen.config import config
|
||||
from ..widgets.progressdialog import (LongOpStatus, ProgressMonitor,
|
||||
GtkProgressDialog)
|
||||
|
||||
def display_message(message):
|
||||
"""
|
||||
@ -1050,3 +1062,175 @@ class ToolManagedWindow(tool.Tool, ToolManagedWindowBase):
|
||||
tool.Tool.__init__(self, dbstate, options_class, name)
|
||||
ToolManagedWindowBase.__init__(self, dbstate, uistate, options_class,
|
||||
name, callback)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# UpdateAddons
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class UpdateAddons(ManagedWindow):
|
||||
|
||||
def __init__(self, uistate, track, addon_update_list):
|
||||
self.title = _('Available Gramps Updates for Addons')
|
||||
ManagedWindow.__init__(self, uistate, track, self.__class__)
|
||||
|
||||
glade = Glade("updateaddons.glade")
|
||||
self.update_dialog = glade.toplevel
|
||||
self.set_window(self.update_dialog, glade.get_object('title'),
|
||||
self.title)
|
||||
self.window.set_size_request(750, 400)
|
||||
|
||||
apply_button = glade.get_object('apply')
|
||||
cancel_button = glade.get_object('cancel')
|
||||
select_all = glade.get_object('select_all')
|
||||
select_all.connect("clicked", self.select_all_clicked)
|
||||
select_none = glade.get_object('select_none')
|
||||
select_none.connect("clicked", self.select_none_clicked)
|
||||
apply_button.connect("clicked", self.install_addons)
|
||||
cancel_button.connect("clicked", self.close)
|
||||
|
||||
self.list = ListModel(glade.get_object("list"), [
|
||||
# name, click?, width, toggle
|
||||
{"name": _('Select'),
|
||||
"width": 60,
|
||||
"type": TOGGLE,
|
||||
"visible_col": 6,
|
||||
"editable": True}, # 0 selected?
|
||||
(_('Type'), 1, 180), # 1 new gramplet
|
||||
(_('Name'), 2, 200), # 2 name (version)
|
||||
(_('Description'), 3, 200), # 3 description
|
||||
('', NOSORT, 0), # 4 url
|
||||
('', NOSORT, 0), # 5 id
|
||||
{"name": '', "type": TOGGLE}, # 6 visible? bool
|
||||
], list_mode="tree")
|
||||
pos = None
|
||||
addon_update_list.sort(key=lambda x: "%s %s" % (x[0], x[2]["t"]))
|
||||
last_category = None
|
||||
for (status,plugin_url,plugin_dict) in addon_update_list:
|
||||
count = get_count(addon_update_list, plugin_dict["t"])
|
||||
category = _("%(adjective)s: %(addon)s") % {
|
||||
"adjective": status,
|
||||
"addon": _(plugin_dict["t"])}
|
||||
if last_category != category:
|
||||
last_category = category
|
||||
node = self.list.add([False, # initially selected?
|
||||
category,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
False]) # checkbox visible?
|
||||
iter = self.list.add([False, # initially selected?
|
||||
"%s %s" % (status, _(plugin_dict["t"])),
|
||||
"%s (%s)" % (plugin_dict["n"],
|
||||
plugin_dict["v"]),
|
||||
plugin_dict["d"],
|
||||
plugin_url,
|
||||
plugin_dict["i"],
|
||||
True], node=node)
|
||||
if pos is None:
|
||||
pos = iter
|
||||
if pos:
|
||||
self.list.selection.select_iter(pos)
|
||||
self.update_dialog.run()
|
||||
|
||||
def build_menu_names(self, obj):
|
||||
return (self.title, "")
|
||||
|
||||
def select_all_clicked(self, widget):
|
||||
"""
|
||||
Select all of the addons for download.
|
||||
"""
|
||||
self.list.model.foreach(update_rows, True)
|
||||
self.list.tree.expand_all()
|
||||
|
||||
def select_none_clicked(self, widget):
|
||||
"""
|
||||
Select none of the addons for download.
|
||||
"""
|
||||
self.list.model.foreach(update_rows, False)
|
||||
self.list.tree.expand_all()
|
||||
|
||||
def install_addons(self, obj):
|
||||
"""
|
||||
Process all of the selected addons.
|
||||
"""
|
||||
self.update_dialog.hide()
|
||||
model = self.list.model
|
||||
|
||||
iter = model.get_iter_first()
|
||||
length = 0
|
||||
while iter:
|
||||
iter = model.iter_next(iter)
|
||||
if iter:
|
||||
length += model.iter_n_children(iter)
|
||||
|
||||
longop = LongOpStatus(
|
||||
_("Downloading and installing selected addons..."),
|
||||
length, 1, # total, increment-by
|
||||
can_cancel=True)
|
||||
pm = ProgressMonitor(GtkProgressDialog,
|
||||
("Title", self.window, Gtk.DialogFlags.MODAL))
|
||||
pm.add_op(longop)
|
||||
count = 0
|
||||
if not config.get('behavior.do-not-show-previously-seen-updates'):
|
||||
# reset list
|
||||
config.get('behavior.previously-seen-updates')[:] = []
|
||||
|
||||
iter = model.get_iter_first()
|
||||
while iter:
|
||||
for rowcnt in range(model.iter_n_children(iter)):
|
||||
child = model.iter_nth_child(iter, rowcnt)
|
||||
row = [model.get_value(child, n) for n in range(6)]
|
||||
if longop.should_cancel():
|
||||
break
|
||||
elif row[0]: # toggle on
|
||||
load_addon_file(row[4], callback=LOG.debug)
|
||||
count += 1
|
||||
else: # add to list of previously seen, but not installed
|
||||
if row[5] not in config.get('behavior.previously-seen-updates'):
|
||||
config.get('behavior.previously-seen-updates').append(row[5])
|
||||
longop.heartbeat()
|
||||
pm._get_dlg()._process_events()
|
||||
iter = model.iter_next(iter)
|
||||
|
||||
if not longop.was_cancelled():
|
||||
longop.end()
|
||||
if count:
|
||||
OkDialog(_("Done downloading and installing addons"),
|
||||
"%s %s" % (glocale.translation.ngettext("%d addon was installed.",
|
||||
"%d addons were installed.",
|
||||
count) % count,
|
||||
_("You need to restart Gramps to see new views.")),
|
||||
self.window)
|
||||
else:
|
||||
OkDialog(_("Done downloading and installing addons"),
|
||||
_("No addons were installed."),
|
||||
self.window)
|
||||
self.close()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Local Functions
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def update_rows(model, path, iter, user_data):
|
||||
"""
|
||||
Update the rows of a model.
|
||||
"""
|
||||
#path: (8,) iter: <GtkTreeIter at 0xbfa89fa0>
|
||||
#path: (8, 0) iter: <GtkTreeIter at 0xbfa89f60>
|
||||
if len(path.get_indices()) == 2:
|
||||
row = model[path]
|
||||
row[0] = user_data
|
||||
model.row_changed(path, iter)
|
||||
|
||||
def get_count(addon_update_list, category):
|
||||
"""
|
||||
Get the count of matching category items.
|
||||
"""
|
||||
count = 0
|
||||
for (status,plugin_url,plugin_dict) in addon_update_list:
|
||||
if plugin_dict["t"] == category and plugin_url:
|
||||
count += 1
|
||||
return count
|
||||
|
@ -34,6 +34,7 @@ from __future__ import print_function, division
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.gettext
|
||||
# gtk is not included here, because this file is currently imported
|
||||
@ -46,6 +47,7 @@ _ = glocale.translation.gettext
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gi.repository import PangoCairo
|
||||
from gi.repository import GLib
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -55,6 +57,7 @@ from gi.repository import PangoCairo
|
||||
from gramps.gen.lib.person import Person
|
||||
from gramps.gen.constfunc import has_display, is_quartz, mac, win
|
||||
from gramps.gen.config import config
|
||||
from gramps.gen.plug.utils import available_updates
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -506,3 +509,22 @@ def hex_to_color(hex):
|
||||
from gi.repository import Gdk
|
||||
color = Gdk.color_parse(hex)
|
||||
return color
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# AvailableUpdates
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class AvailableUpdates(threading.Thread):
|
||||
def __init__(self, uistate):
|
||||
threading.Thread.__init__(self)
|
||||
self.uistate = uistate
|
||||
self.addon_update_list = []
|
||||
|
||||
def emit_update_available(self):
|
||||
self.uistate.emit('update-available', (self.addon_update_list, ))
|
||||
|
||||
def run(self):
|
||||
self.addon_update_list = available_updates()
|
||||
if len(self.addon_update_list) > 0:
|
||||
GLib.idle_add(self.emit_update_available)
|
||||
|
@ -78,7 +78,7 @@ from gramps.gen.plug import REPORT
|
||||
from gramps.gen.plug.report._constants import standalone_categories
|
||||
from .plug import (PluginWindows, ReportPluginDialog, ToolPluginDialog)
|
||||
from .plug.report import report, BookSelector
|
||||
from gramps.gen.plug.utils import version_str_to_tup, load_addon_file
|
||||
from .utils import AvailableUpdates
|
||||
from .pluginmanager import GuiPluginManager
|
||||
from gramps.gen.relationship import get_relationship_calculator
|
||||
from .displaystate import DisplayState, RecentDocsMenu
|
||||
@ -88,22 +88,19 @@ from gramps.gen.const import (HOME_DIR, ICON, URL_BUGTRACKER, URL_HOMEPAGE,
|
||||
from gramps.gen.constfunc import is_quartz
|
||||
from gramps.gen.config import config
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from .dialog import (ErrorDialog, WarningDialog, QuestionDialog2,
|
||||
InfoDialog)
|
||||
from .dialog import ErrorDialog, WarningDialog, QuestionDialog2, InfoDialog
|
||||
from .widgets import Statusbar
|
||||
from .undohistory import UndoHistory
|
||||
from gramps.gen.utils.file import (media_path_full, get_unicode_path_from_env_var,
|
||||
get_unicode_path_from_file_chooser)
|
||||
from .dbloader import DbLoader
|
||||
from .display import display_help, display_url
|
||||
from .widgets.progressdialog import ProgressMonitor, GtkProgressDialog
|
||||
from .configure import GrampsPreferences
|
||||
from gramps.gen.db.backup import backup
|
||||
from gramps.gen.db.exceptions import DbException
|
||||
from .aboutdialog import GrampsAboutDialog
|
||||
from .navigator import Navigator
|
||||
from .views.tags import Tags
|
||||
from gramps.gen.utils.configmanager import safe_eval
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -239,32 +236,6 @@ WIKI_HELP_PAGE_FAQ = '%s_-_FAQ' % URL_MANUAL_PAGE
|
||||
WIKI_HELP_PAGE_KEY = '%s_-_Keybindings' % URL_MANUAL_PAGE
|
||||
WIKI_HELP_PAGE_MAN = '%s' % URL_MANUAL_PAGE
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Local Functions
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def update_rows(model, path, iter, user_data):
|
||||
"""
|
||||
Update the rows of a model.
|
||||
"""
|
||||
#path: (8,) iter: <GtkTreeIter at 0xbfa89fa0>
|
||||
#path: (8, 0) iter: <GtkTreeIter at 0xbfa89f60>
|
||||
if len(path.get_indices()) == 2:
|
||||
row = model[path]
|
||||
row[0] = user_data
|
||||
model.row_changed(path, iter)
|
||||
|
||||
def get_count(addon_update_list, category):
|
||||
"""
|
||||
Get the count of matching category items.
|
||||
"""
|
||||
count = 0
|
||||
for (status,plugin_url,plugin_dict) in addon_update_list:
|
||||
if plugin_dict["t"] == category and plugin_url:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# ViewManager
|
||||
@ -343,17 +314,16 @@ class ViewManager(CLIManager):
|
||||
self.rel_class = get_relationship_calculator()
|
||||
self.uistate.set_relationship_class()
|
||||
# Need to call after plugins have been registered
|
||||
self.uistate.connect('update-available', self.process_updates)
|
||||
self.check_for_updates()
|
||||
|
||||
def check_for_updates(self, force=False):
|
||||
def check_for_updates(self):
|
||||
"""
|
||||
Check for add-on updates.
|
||||
"""
|
||||
howoften = config.get("behavior.check-for-updates")
|
||||
whattypes = config.get('behavior.check-for-update-types')
|
||||
update = False
|
||||
if force:
|
||||
update = True
|
||||
elif howoften != 0: # update never if zero
|
||||
if howoften != 0: # update never if zero
|
||||
y,m,d = list(map(int,
|
||||
config.get("behavior.last-check-for-updates").split("/")))
|
||||
days = (datetime.date.today() - datetime.date(y, m, d)).days
|
||||
@ -365,238 +335,20 @@ class ViewManager(CLIManager):
|
||||
update = True
|
||||
elif howoften == 4: # always
|
||||
update = True
|
||||
|
||||
if update:
|
||||
if sys.version_info[0] < 3:
|
||||
from urllib2 import urlopen
|
||||
else:
|
||||
from urllib.request import urlopen
|
||||
LOG.debug("Checking for updated addons...")
|
||||
langs = glocale.get_language_list()
|
||||
langs.append("en")
|
||||
# now we have a list of languages to try:
|
||||
fp = None
|
||||
for lang in langs:
|
||||
URL = ("%s/listings/addons-%s.txt" %
|
||||
(config.get("behavior.addons-url"), lang))
|
||||
LOG.debug(" trying: %s" % URL)
|
||||
try:
|
||||
fp = urlopen(URL, timeout=10) # abort after 10 seconds
|
||||
except:
|
||||
try:
|
||||
URL = ("%s/listings/addons-%s.txt" %
|
||||
(config.get("behavior.addons-url"), lang[:2]))
|
||||
fp = urlopen(URL, timeout=10)
|
||||
except Exception as err: # some error
|
||||
LOG.warn("Failed to open %s: %s" % (lang, err))
|
||||
fp = None
|
||||
if fp and fp.getcode() == 200: # ok
|
||||
break
|
||||
addon_update_list = []
|
||||
if fp and fp.getcode() == 200:
|
||||
lines = list(fp.readlines())
|
||||
count = 0
|
||||
for line in lines:
|
||||
line = line.decode('utf-8')
|
||||
try:
|
||||
plugin_dict = safe_eval(line)
|
||||
if type(plugin_dict) != type({}):
|
||||
raise TypeError("Line with addon metadata is not "
|
||||
"a dictionary")
|
||||
except:
|
||||
LOG.warning("Skipped a line in the addon listing: " +
|
||||
str(line))
|
||||
continue
|
||||
id = plugin_dict["i"]
|
||||
plugin = self._pmgr.get_plugin(id)
|
||||
if plugin:
|
||||
LOG.debug("Comparing %s > %s" %
|
||||
(version_str_to_tup(plugin_dict["v"], 3),
|
||||
version_str_to_tup(plugin.version, 3)))
|
||||
if (version_str_to_tup(plugin_dict["v"], 3) >
|
||||
version_str_to_tup(plugin.version, 3)):
|
||||
LOG.debug(" Downloading '%s'..." % plugin_dict["z"])
|
||||
if "update" in whattypes:
|
||||
if (not config.get('behavior.do-not-show-previously-seen-updates') or
|
||||
plugin_dict["i"] not in config.get('behavior.previously-seen-updates')):
|
||||
addon_update_list.append((_("Updated"),
|
||||
"%s/download/%s" %
|
||||
(config.get("behavior.addons-url"),
|
||||
plugin_dict["z"]),
|
||||
plugin_dict))
|
||||
else:
|
||||
LOG.debug(" '%s' is ok" % plugin_dict["n"])
|
||||
else:
|
||||
LOG.debug(" '%s' is not installed" % plugin_dict["n"])
|
||||
if "new" in whattypes:
|
||||
if (not config.get('behavior.do-not-show-previously-seen-updates') or
|
||||
plugin_dict["i"] not in config.get('behavior.previously-seen-updates')):
|
||||
addon_update_list.append((_("New"),
|
||||
"%s/download/%s" %
|
||||
(config.get("behavior.addons-url"),
|
||||
plugin_dict["z"]),
|
||||
plugin_dict))
|
||||
config.set("behavior.last-check-for-updates",
|
||||
datetime.date.today().strftime("%Y/%m/%d"))
|
||||
count += 1
|
||||
if fp:
|
||||
fp.close()
|
||||
else:
|
||||
from .dialog import OkDialog
|
||||
OkDialog(_("Checking Addons Failed"),
|
||||
_("The addon repository appears to be unavailable. Please try again later."),
|
||||
self.window)
|
||||
if fp:
|
||||
fp.close()
|
||||
return
|
||||
LOG.debug("Done checking!")
|
||||
# List of translated strings used here
|
||||
# Dead code for l10n
|
||||
_('new'), _('update')
|
||||
if addon_update_list:
|
||||
self.update_addons(addon_update_list)
|
||||
elif force:
|
||||
from .dialog import OkDialog
|
||||
OkDialog(_("There are no available addons of this type"),
|
||||
_("Checked for '%s'") %
|
||||
_("' and '").join([_(t) for t in config.get('behavior.check-for-update-types')]),
|
||||
self.window)
|
||||
AvailableUpdates(self.uistate).start()
|
||||
|
||||
def update_addons(self, addon_update_list):
|
||||
from .glade import Glade
|
||||
from .managedwindow import set_titles
|
||||
from .listmodel import ListModel, NOSORT, TOGGLE
|
||||
glade = Glade("updateaddons.glade")
|
||||
self.update_dialog = glade.toplevel
|
||||
set_titles(self.update_dialog, glade.get_object('title'),
|
||||
_('Available Gramps Updates for Addons'))
|
||||
apply_button = glade.get_object('apply')
|
||||
cancel_button = glade.get_object('cancel')
|
||||
select_all = glade.get_object('select_all')
|
||||
select_all.connect("clicked", self.select_all_clicked)
|
||||
select_none = glade.get_object('select_none')
|
||||
select_none.connect("clicked", self.select_none_clicked)
|
||||
apply_button.connect("clicked", self.install_addons)
|
||||
cancel_button.connect("clicked",
|
||||
lambda obj: self.update_dialog.destroy())
|
||||
self.list = ListModel(glade.get_object("list"), [
|
||||
# name, click?, width, toggle
|
||||
{"name": _('Select'),
|
||||
"width": 60,
|
||||
"type": TOGGLE,
|
||||
"visible_col": 6,
|
||||
"editable": True}, # 0 selected?
|
||||
(_('Type'), 1, 180), # 1 new gramplet
|
||||
(_('Name'), 2, 200), # 2 name (version)
|
||||
(_('Description'), 3, 200), # 3 description
|
||||
('', NOSORT, 0), # 4 url
|
||||
('', NOSORT, 0), # 5 id
|
||||
{"name": '', "type": TOGGLE}, # 6 visible? bool
|
||||
], list_mode="tree")
|
||||
pos = None
|
||||
addon_update_list.sort(key=lambda x: "%s %s" % (x[0], x[2]["t"]))
|
||||
last_category = None
|
||||
for (status,plugin_url,plugin_dict) in addon_update_list:
|
||||
count = get_count(addon_update_list, plugin_dict["t"])
|
||||
category = _("%(adjective)s: %(addon)s") % {
|
||||
"adjective": status,
|
||||
"addon": _(plugin_dict["t"])}
|
||||
if last_category != category:
|
||||
last_category = category
|
||||
node = self.list.add([False, # initially selected?
|
||||
category,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
False]) # checkbox visible?
|
||||
iter = self.list.add([False, # initially selected?
|
||||
"%s %s" % (status, _(plugin_dict["t"])),
|
||||
"%s (%s)" % (plugin_dict["n"],
|
||||
plugin_dict["v"]),
|
||||
plugin_dict["d"],
|
||||
plugin_url,
|
||||
plugin_dict["i"],
|
||||
True], node=node)
|
||||
if pos is None:
|
||||
pos = iter
|
||||
if pos:
|
||||
self.list.selection.select_iter(pos)
|
||||
self.update_dialog.run()
|
||||
|
||||
def select_all_clicked(self, widget):
|
||||
def process_updates(self, addon_update_list):
|
||||
"""
|
||||
Select all of the addons for download.
|
||||
Called when add-on updates are available.
|
||||
"""
|
||||
self.list.model.foreach(update_rows, True)
|
||||
self.list.tree.expand_all()
|
||||
try:
|
||||
PluginWindows.UpdateAddons(self.uistate, [], addon_update_list)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
|
||||
def select_none_clicked(self, widget):
|
||||
"""
|
||||
Select none of the addons for download.
|
||||
"""
|
||||
self.list.model.foreach(update_rows, False)
|
||||
self.list.tree.expand_all()
|
||||
|
||||
def install_addons(self, obj):
|
||||
"""
|
||||
Process all of the selected addons.
|
||||
"""
|
||||
from .dialog import OkDialog
|
||||
from .widgets.progressdialog import LongOpStatus
|
||||
self.update_dialog.hide()
|
||||
model = self.list.model
|
||||
|
||||
iter = model.get_iter_first()
|
||||
length = 0
|
||||
while iter:
|
||||
iter = model.iter_next(iter)
|
||||
if iter:
|
||||
length += model.iter_n_children(iter)
|
||||
|
||||
longop = LongOpStatus(
|
||||
_("Downloading and installing selected addons..."),
|
||||
length, 1, # total, increment-by
|
||||
can_cancel=True)
|
||||
pm = ProgressMonitor(GtkProgressDialog,
|
||||
("Title", self.window, Gtk.DialogFlags.MODAL))
|
||||
pm.add_op(longop)
|
||||
count = 0
|
||||
if not config.get('behavior.do-not-show-previously-seen-updates'):
|
||||
# reset list
|
||||
config.get('behavior.previously-seen-updates')[:] = []
|
||||
|
||||
iter = model.get_iter_first()
|
||||
while iter:
|
||||
for rowcnt in range(model.iter_n_children(iter)):
|
||||
child = model.iter_nth_child(iter, rowcnt)
|
||||
row = [model.get_value(child, n) for n in range(6)]
|
||||
if longop.should_cancel():
|
||||
break
|
||||
elif row[0]: # toggle on
|
||||
load_addon_file(row[4], callback=LOG.debug)
|
||||
count += 1
|
||||
else: # add to list of previously seen, but not installed
|
||||
if row[5] not in config.get('behavior.previously-seen-updates'):
|
||||
config.get('behavior.previously-seen-updates').append(row[5])
|
||||
longop.heartbeat()
|
||||
pm._get_dlg()._process_events()
|
||||
iter = model.iter_next(iter)
|
||||
|
||||
if not longop.was_cancelled():
|
||||
longop.end()
|
||||
if count:
|
||||
self.do_reg_plugins(self.dbstate, self.uistate)
|
||||
OkDialog(_("Done downloading and installing addons"),
|
||||
"%s %s" % (glocale.translation.ngettext("%d addon was installed.",
|
||||
"%d addons were installed.",
|
||||
count) % count,
|
||||
_("You need to restart Gramps to see new views.")),
|
||||
self.window)
|
||||
else:
|
||||
OkDialog(_("Done downloading and installing addons"),
|
||||
_("No addons were installed."),
|
||||
self.window)
|
||||
self.update_dialog.destroy()
|
||||
self.do_reg_plugins(self.dbstate, self.uistate)
|
||||
|
||||
def _errordialog(self, title, errormessage):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user