PluginInstallerPlugin.gtk3 support

This commit is contained in:
Denis Fomin
2013-01-27 21:38:10 +04:00
parent f4ad05a45a
commit e3b08b6cb7
6 changed files with 114 additions and 106 deletions

View File

@@ -1 +1 @@
from plugin_installer import PluginInstaller
from .plugin_installer import PluginInstaller

View File

@@ -62,9 +62,12 @@
<object class="GtkLabel" id="plugin_name_label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label">&lt;empty&gt;</property>
<property name="label">empty</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -6,4 +6,4 @@ description: Install and upgrade plugins from ftp
authors: Denis Fomin <fominde@gmail.com>
Yann Leboulanger <asterix@lagaule.org>
homepage: http://trac-plugins.gajim.org/wiki/PluginInstallerPlugin
max_gajim_version: 0.15.9
min_gajim_version: 0.15.10

View File

@@ -19,13 +19,14 @@
## You should have received a copy of the GNU General Public License
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
import gtk
import pango
import gobject
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import Pango
from gi.repository import GObject
import ftplib
import io
import threading
import ConfigParser
import configparser
import os
import fnmatch
import sys
@@ -61,7 +62,7 @@ class PluginInstaller(GajimPlugin):
@log_calls('PluginInstallerPlugin')
def init(self):
self.description = _('Install and upgrade plugins from ftp')
self.config_dialog = PluginInstallerPluginConfigDialog(self)
#self.config_dialog = PluginInstallerPluginConfigDialog(self)
self.config_default_values = {'ftp_server': ('ftp.gajim.org', ''),
'check_update': (True, ''),
'TLS': (True, ''),}
@@ -71,9 +72,9 @@ class PluginInstaller(GajimPlugin):
self.upgrading = False # True when opened from upgrade popup dialog
self.timeout_id = 0
self.connected_ids = {}
icon = gtk.Image()
self.def_icon = icon.render_icon(gtk.STOCK_PREFERENCES,
gtk.ICON_SIZE_MENU)
icon = Gtk.Image()
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
Gtk.IconSize.MENU)
@log_calls('PluginInstallerPlugin')
def activate(self):
@@ -83,7 +84,7 @@ class PluginInstaller(GajimPlugin):
if 'plugins' in gajim.interface.instances:
self.on_activate(None)
if self.config['check_update']:
self.timeout_id = gobject.timeout_add_seconds(30, self.check_update)
self.timeout_id = GObject.timeout_add_seconds(30, self.check_update)
@log_calls('PluginInstallerPlugin')
def warn_update(self, plugins):
@@ -91,7 +92,7 @@ class PluginInstaller(GajimPlugin):
self.upgrading = True
self.pl_menuitem.activate()
nb = gajim.interface.instances['plugins'].plugins_notebook
gobject.idle_add(nb.set_current_page, 1)
GObject.idle_add(nb.set_current_page, 1)
if plugins:
plugins_str = '\n'.join(plugins)
YesNoDialog(_('Plugins updates'), _('Some updates are available for'
@@ -119,8 +120,10 @@ class PluginInstaller(GajimPlugin):
zip_file = zipfile.ZipFile(ftp.buffer_)
manifest_list = zip_file.namelist()
for filename in manifest_list:
config = ConfigParser.ConfigParser()
config.readfp(zip_file.open(filename))
config = configparser.ConfigParser()
conf_file = zip_file.open(filename)
config.read_file(io.TextIOWrapper(conf_file, encoding='utf-8'))
conf_file.close()
if not config.has_section('info'):
continue
opts = config.options('info')
@@ -137,8 +140,8 @@ class PluginInstaller(GajimPlugin):
if remote > local:
to_update.append(config.get('info', 'name'))
con.quit()
gobject.idle_add(self.warn_update, to_update)
except Exception, e:
GObject.idle_add(self.warn_update, to_update)
except Exception as e:
log.debug('Ftp error when check updates: %s' % str(e))
ftp = Ftp(self)
ftp.run = _run
@@ -151,13 +154,13 @@ class PluginInstaller(GajimPlugin):
if hasattr(self, 'page_num'):
self.notebook.remove_page(self.page_num)
self.notebook.set_current_page(0)
for id_, widget in self.connected_ids.items():
for id_, widget in list(self.connected_ids.items()):
widget.disconnect(id_)
del self.page_num
if hasattr(self, 'ftp'):
del self.ftp
if self.timeout_id > 0:
gobject.source_remove(self.timeout_id)
GObject.source_remove(self.timeout_id)
self.timeout_id = 0
def on_activate(self, widget):
@@ -174,13 +177,13 @@ class PluginInstaller(GajimPlugin):
self.window = gajim.interface.instances['plugins'].window
id_ = self.window.connect('destroy', self.on_win_destroy)
self.connected_ids[id_] = self.window
self.GTK_BUILDER_FILE_PATH = self.local_file_path('config_dialog.ui')
self.xml = gtk.Builder()
self.Gtk_BUILDER_FILE_PATH = self.local_file_path('config_dialog.ui')
self.xml = Gtk.Builder()
self.xml.set_translation_domain('gajim_plugins')
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH, ['hpaned2'])
self.xml.add_objects_from_file(self.Gtk_BUILDER_FILE_PATH, ['hpaned2'])
hpaned = self.xml.get_object('hpaned2')
self.page_num = self.notebook.append_page(hpaned,
gtk.Label(_('Available')))
Gtk.Label(_('Available')))
widgets_to_extract = ('plugin_name_label1',
'available_treeview', 'progressbar', 'inslall_upgrade_button',
@@ -190,52 +193,55 @@ class PluginInstaller(GajimPlugin):
for widget_name in widgets_to_extract:
setattr(self, widget_name, self.xml.get_object(widget_name))
attr_list = pango.AttrList()
attr_list.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
self.plugin_name_label1.set_attributes(attr_list)
##attr_list = Pango.AttrList()
##attr_list.insert(Pango.AttrSize(Pango.Weight.BOLD))
#fd = Pango.FontDescription()
#fd.set_weight(Pango.Weight.BOLD)
#self.plugin_name_label1.modify_font(fd)
##self.plugin_name_label1.set_attributes(attr_list)
self.available_plugins_model = gtk.ListStore(gtk.gdk.Pixbuf,
gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING,
gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT,
gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)
self.available_plugins_model = Gtk.ListStore(GdkPixbuf.Pixbuf,
GObject.TYPE_PYOBJECT, GObject.TYPE_STRING, GObject.TYPE_STRING,
GObject.TYPE_STRING, GObject.TYPE_BOOLEAN, GObject.TYPE_PYOBJECT,
GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT)
self.available_treeview.set_model(self.available_plugins_model)
self.available_treeview.set_rules_hint(True)
self.available_plugins_model.set_sort_column_id(2, gtk.SORT_ASCENDING)
self.available_plugins_model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
self.progressbar.set_property('no-show-all', True)
renderer = gtk.CellRendererText()
col = gtk.TreeViewColumn(_('Plugin'))
cell = gtk.CellRendererPixbuf()
renderer = Gtk.CellRendererText()
col = Gtk.TreeViewColumn(_('Plugin'))
cell = Gtk.CellRendererPixbuf()
col.pack_start(cell, False)
col.add_attribute(cell, 'pixbuf', C_PIXBUF)
col.pack_start(renderer, True)
col.add_attribute(renderer, 'text', C_NAME)
col.set_resizable(True)
col.set_property('expand', True)
col.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY)
col.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY)
self.available_treeview.append_column(col)
col = gtk.TreeViewColumn(_('Installed\nversion'), renderer,
col = Gtk.TreeViewColumn(_('Installed\nversion'), renderer,
text=C_LOCAL_VERSION)
self.available_treeview.append_column(col)
col = gtk.TreeViewColumn(_('Available\nversion'), renderer,
col = Gtk.TreeViewColumn(_('Available\nversion'), renderer,
text=C_VERSION)
col.set_property('expand', False)
self.available_treeview.append_column(col)
renderer = gtk.CellRendererToggle()
renderer = Gtk.CellRendererToggle()
renderer.set_property('activatable', True)
renderer.connect('toggled', self.available_plugins_toggled_cb)
col = gtk.TreeViewColumn(_('Install /\nUpgrade'), renderer,
col = Gtk.TreeViewColumn(_('Install /\nUpgrade'), renderer,
active=C_UPGRADE)
self.available_treeview.append_column(col)
if gobject.signal_lookup('error_signal', self.window) is 0:
gobject.signal_new('error_signal', self.window,
gobject.SIGNAL_RUN_LAST, gobject.TYPE_STRING,
(gobject.TYPE_STRING,))
gobject.signal_new('plugin_downloaded', self.window,
gobject.SIGNAL_RUN_LAST, gobject.TYPE_STRING,
(gobject.TYPE_PYOBJECT,))
if GObject.signal_lookup('error_signal', self.window) is 0:
GObject.signal_new('error_signal', self.window,
GObject.SIGNAL_RUN_LAST, GObject.TYPE_STRING,
(GObject.TYPE_STRING,))
GObject.signal_new('plugin_downloaded', self.window,
GObject.SIGNAL_RUN_LAST, GObject.TYPE_STRING,
(GObject.TYPE_PYOBJECT,))
id_ = self.window.connect('error_signal', self.on_some_ftp_error)
self.connected_ids[id_] = self.window
id_ = self.window.connect('plugin_downloaded',
@@ -245,7 +251,7 @@ class PluginInstaller(GajimPlugin):
selection = self.available_treeview.get_selection()
selection.connect('changed',
self.available_plugins_treeview_selection_changed)
selection.set_mode(gtk.SELECTION_SINGLE)
selection.set_mode(Gtk.SelectionMode.SINGLE)
self._clear_available_plugin_info()
self.xml.connect_signals(self)
@@ -261,7 +267,7 @@ class PluginInstaller(GajimPlugin):
is_active = self.available_plugins_model[path][C_UPGRADE]
self.available_plugins_model[path][C_UPGRADE] = not is_active
dir_list = []
for i in xrange(len(self.available_plugins_model)):
for i in range(len(self.available_plugins_model)):
if self.available_plugins_model[i][C_UPGRADE]:
dir_list.append(self.available_plugins_model[i][C_DIR])
if not dir_list:
@@ -281,7 +287,7 @@ class PluginInstaller(GajimPlugin):
def on_inslall_upgrade_clicked(self, widget):
self.inslall_upgrade_button.set_property('sensitive', False)
dir_list = []
for i in xrange(len(self.available_plugins_model)):
for i in range(len(self.available_plugins_model)):
if self.available_plugins_model[i][C_UPGRADE]:
dir_list.append(self.available_plugins_model[i][C_DIR])
@@ -290,13 +296,13 @@ class PluginInstaller(GajimPlugin):
ftp.start()
def on_some_ftp_error(self, widget, error_text):
for i in xrange(len(self.available_plugins_model)):
for i in range(len(self.available_plugins_model)):
self.available_plugins_model[i][C_UPGRADE] = False
self.progressbar.hide()
WarningDialog(_('Ftp error'), error_text, self.window)
def on_plugin_downloaded(self, widget, plugin_dirs):
dialog = HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
dialog = HigDialog(None, Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
'', _('All selected plugins downloaded'))
dialog.set_modal(False)
dialog.set_transient_for(self.window)
@@ -309,12 +315,12 @@ class PluginInstaller(GajimPlugin):
if plugin:
if plugin.active:
is_active = True
gobject.idle_add(gajim.plugin_manager.deactivate_plugin,
GObject.idle_add(gajim.plugin_manager.deactivate_plugin,
plugin)
gajim.plugin_manager.plugins.remove(plugin)
model = self.installed_plugins_model
for row in xrange(len(model)):
for row in range(len(model)):
if plugin == model[row][0]:
model.remove(model.get_iter((row, 0)))
break
@@ -324,26 +330,23 @@ class PluginInstaller(GajimPlugin):
continue
gajim.plugin_manager.add_plugin(plugins[0])
plugin = gajim.plugin_manager.plugins[-1]
for row in xrange(len(self.available_plugins_model)):
for row in range(len(self.available_plugins_model)):
if plugin.name == self.available_plugins_model[row][C_NAME]:
self.available_plugins_model[row][C_LOCAL_VERSION] = \
plugin.version
self.available_plugins_model[row][C_UPGRADE] = False
if is_active:
gobject.idle_add(gajim.plugin_manager.activate_plugin, plugin)
GObject.idle_add(gajim.plugin_manager.activate_plugin, plugin)
# get plugin icon
icon_file = os.path.join(plugin.__path__, os.path.split(
plugin.__path__)[1]) + '.png'
icon = self.def_icon
if os.path.isfile(icon_file):
icon = gtk.gdk.pixbuf_new_from_file_at_size(icon_file, 16, 16)
icon = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file, 16, 16)
if not hasattr(plugin, 'activatable'):
# version 0.15
plugin.activatable = False
max_row = [plugin, plugin.name, is_active, plugin.activatable, icon]
# support old plugin system
row_len = len(self.installed_plugins_model[0])
row = max_row[0: row_len]
row = [plugin, plugin.name, is_active, plugin.activatable, icon]
self.installed_plugins_model.append(row)
dialog.popup()
@@ -358,7 +361,7 @@ class PluginInstaller(GajimPlugin):
self.plugin_homepage_linkbutton1.set_label(model.get_value(iter,
C_HOMEPAGE))
label = self.plugin_homepage_linkbutton1.get_children()[0]
label.set_ellipsize(pango.ELLIPSIZE_END)
label.set_ellipsize(Pango.EllipsizeMode.END)
self.plugin_homepage_linkbutton1.set_property('sensitive', True)
desc_textbuffer = self.plugin_description_textview1.get_buffer()
desc_textbuffer.set_text(_(model.get_value(iter, C_DESCRIPTION)))
@@ -379,7 +382,7 @@ class PluginInstaller(GajimPlugin):
def scan_dir_for_plugin(self, path):
plugins_found = []
conf = ConfigParser.ConfigParser()
conf = configparser.ConfigParser()
fields = ('name', 'short_name', 'version', 'description', 'authors',
'homepage')
if not os.path.isdir(path):
@@ -404,14 +407,15 @@ class PluginInstaller(GajimPlugin):
try:
full_module_name = '%s.%s' % (mod, module_name)
if full_module_name in sys.modules:
from imp import reload
module = reload(sys.modules[full_module_name])
else:
module = __import__(full_module_name)
except ValueError, value_error:
except ValueError as value_error:
pass
except ImportError, import_error:
except ImportError as import_error:
pass
except AttributeError, attribute_error:
except AttributeError as attribute_error:
pass
if module is None:
continue
@@ -430,14 +434,14 @@ class PluginInstaller(GajimPlugin):
conf.readfp(open(manifest_path, 'r'))
for option in fields:
if conf.get('info', option) is '':
raise ConfigParser.NoOptionError, 'field empty'
raise configparser.NoOptionError('field empty')
setattr(module_attr, option, conf.get('info', option))
conf.remove_section('info')
plugins_found.append(module_attr)
except TypeError, type_error:
except TypeError as type_error:
pass
except ConfigParser.NoOptionError, type_error:
except configparser.NoOptionError as type_error:
# all fields are required
pass
return plugins_found
@@ -446,7 +450,7 @@ class PluginInstaller(GajimPlugin):
if hasattr(self, 'page_num'):
selection = self.available_treeview.get_selection()
if selection.count_selected_rows() == 0:
root_iter = self.available_plugins_model.get_iter_root()
root_iter = self.available_plugins_model.get_iter_first()
selection.select_iter(root_iter)
scr_win = self.xml.get_object('scrolledwindow2')
scr_win.get_vadjustment().set_value(0)
@@ -463,9 +467,9 @@ class Ftp(threading.Thread):
self.remote_dirs = None
self.append_to_model = True
self.upgrading = False
icon = gtk.Image()
self.def_icon = icon.render_icon(gtk.STOCK_PREFERENCES,
gtk.ICON_SIZE_MENU)
icon = Gtk.Image()
self.def_icon = icon.render_icon(Gtk.STOCK_PREFERENCES,
Gtk.IconSize.MENU)
def model_append(self, row):
self.model.append(row)
@@ -482,12 +486,13 @@ class Ftp(threading.Thread):
def run(self):
try:
gobject.idle_add(self.progressbar.set_text,
GObject.idle_add(self.progressbar.set_text,
_('Connecting to server'))
self.ftp = self.plugin.ftp_connect()
self.ftp.cwd('plugins')
self.progressbar.set_show_text(True)
if not self.remote_dirs:
gobject.idle_add(self.progressbar.set_text,
GObject.idle_add(self.progressbar.set_text,
_('Scan files on the server'))
self.ftp.retrbinary('RETR manifests_images.zip', self.handleDownload)
zip_file = zipfile.ZipFile(self.buffer_)
@@ -498,12 +503,14 @@ class Ftp(threading.Thread):
continue
dir_ = filename.split('/')[0]
fract = self.progressbar.get_fraction() + progress_step
gobject.idle_add(self.progressbar.set_fraction, fract)
gobject.idle_add(self.progressbar.set_text,
GObject.idle_add(self.progressbar.set_fraction, fract)
GObject.idle_add(self.progressbar.set_text,
_('Reading "%s"') % dir_)
config = ConfigParser.ConfigParser()
config.readfp(zip_file.open(filename))
config = configparser.ConfigParser()
conf_file = zip_file.open(filename)
config.read_file(io.TextIOWrapper(conf_file, encoding='utf-8'))
conf_file.close()
if not config.has_section('info'):
continue
opts = config.options('info')
@@ -521,13 +528,13 @@ class Ftp(threading.Thread):
'version'))
if remote > local:
upgrade = True
gobject.idle_add(
GObject.idle_add(
self.plugin.inslall_upgrade_button.set_property,
'sensitive', True)
png_filename = dir_ + '/' + dir_ + '.png'
if png_filename in manifest_list:
data = zip_file.open(png_filename).read()
pbl = gtk.gdk.PixbufLoader()
pbl = GdkPixbuf.PixbufLoader()
pbl.set_size(16, 16)
pbl.write(data)
pbl.close()
@@ -538,28 +545,28 @@ class Ftp(threading.Thread):
base_dir, user_dir = gajim.PLUGINS_DIRS
local_dir = os.path.join(user_dir, dir_)
gobject.idle_add(self.model_append, [def_icon, dir_,
GObject.idle_add(self.model_append, [def_icon, dir_,
config.get('info', 'name'), local_version,
config.get('info', 'version'), upgrade,
config.get('info', 'description'),
config.get('info', 'authors'),
config.get('info', 'homepage'), ])
self.ftp.quit()
gobject.idle_add(self.progressbar.set_fraction, 0)
GObject.idle_add(self.progressbar.set_fraction, 0)
if self.remote_dirs:
self.download_plugin()
gobject.idle_add(self.progressbar.hide)
gobject.idle_add(self.plugin.select_root_iter)
except Exception, e:
GObject.idle_add(self.progressbar.hide)
GObject.idle_add(self.plugin.select_root_iter)
except Exception as e:
self.window.emit('error_signal', str(e))
def handleDownload(self, block):
self.buffer_.write(block)
def download_plugin(self):
gobject.idle_add(self.progressbar.show)
self.pulse = gobject.timeout_add(150, self.progressbar_pulse)
gobject.idle_add(self.progressbar.set_text, _('Creating a list of files'))
GObject.idle_add(self.progressbar.show)
self.pulse = GObject.timeout_add(150, self.progressbar_pulse)
GObject.idle_add(self.progressbar.set_text, _('Creating a list of files'))
for remote_dir in self.remote_dirs:
def nlstr(dir_, subdir=None):
@@ -573,7 +580,7 @@ class Ftp(threading.Thread):
if i == self.ftp.nlst(i)[0]:
files.append(i[1:])
del dirs[i[1:]]
except Exception, e:
except Exception as e:
# empty dir or file
continue
dirs.append(i[1:])
@@ -596,36 +603,37 @@ class Ftp(threading.Thread):
for dir_ in dirs:
try:
os.mkdir(os.path.join(local_dir, dir_))
except OSError, e:
except OSError as e:
if str(e).startswith('[Errno 17]'):
continue
raise
# downloading files
for filename in files:
gobject.idle_add(self.progressbar.set_text,
GObject.idle_add(self.progressbar.set_text,
_('Downloading "%s"') % filename)
full_filename = os.path.join(local_dir, filename)
try:
file_ = open(full_filename, 'wb')
self.ftp.retrbinary('RETR /%s' % filename,
open(full_filename, 'wb').write)
#full_filename.close()
file_.write)
file_.close()
except ftplib.error_perm:
print 'ERROR: cannot read file "%s"' % filename
print('ERROR: cannot read file "%s"' % filename)
os.unlink(filename)
self.ftp.quit()
gobject.idle_add(self.window.emit, 'plugin_downloaded',
GObject.idle_add(self.window.emit, 'plugin_downloaded',
self.remote_dirs)
gobject.source_remove(self.pulse)
GObject.source_remove(self.pulse)
class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog):
def init(self):
self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
self.Gtk_BUILDER_FILE_PATH = self.plugin.local_file_path(
'config_dialog.ui')
self.xml = gtk.Builder()
self.xml = Gtk.Builder()
self.xml.set_translation_domain('gajim_plugins')
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH, ['hbox111'])
self.xml.add_objects_from_file(self.Gtk_BUILDER_FILE_PATH, ['hbox111'])
hbox = self.xml.get_object('hbox111')
self.child.pack_start(hbox)