[kepi] ability to use subkeys. Fixes #6051
[gajim.git] / src / plugins / gui.py
blobd095b3da336ff38639f55bf66018492855180f11
1 # -*- coding: utf-8 -*-
3 ## This file is part of Gajim.
4 ##
5 ## Gajim is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published
7 ## by the Free Software Foundation; version 3 only.
8 ##
9 ## Gajim is distributed in the hope that it will be useful,
10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details.
14 ## You should have received a copy of the GNU General Public License
15 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
18 '''
19 GUI classes related to plug-in management.
21 :author: Mateusz Biliński <mateusz@bilinski.it>
22 :since: 6th June 2008
23 :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
24 :license: GPL
25 '''
27 __all__ = ['PluginsWindow']
29 import pango
30 import gtk, gobject
32 import gtkgui_helpers
33 from dialogs import WarningDialog, YesNoDialog, ArchiveChooserDialog
34 from common import gajim
35 from plugins.helpers import log_calls, log
36 from plugins.helpers import GajimPluginActivateException
37 from common.exceptions import PluginsystemError
39 class PluginsWindow(object):
40 '''Class for Plugins window'''
42 @log_calls('PluginsWindow')
43 def __init__(self):
44 '''Initialize Plugins window'''
45 self.xml = gtkgui_helpers.get_gtk_builder('plugins_window.ui')
46 self.window = self.xml.get_object('plugins_window')
47 self.window.set_transient_for(gajim.interface.roster.window)
49 widgets_to_extract = ('plugins_notebook', 'plugin_name_label',
50 'plugin_version_label', 'plugin_authors_label',
51 'plugin_homepage_linkbutton', 'plugin_description_textview',
52 'uninstall_plugin_button', 'configure_plugin_button',
53 'installed_plugins_treeview')
55 for widget_name in widgets_to_extract:
56 setattr(self, widget_name, self.xml.get_object(widget_name))
58 attr_list = pango.AttrList()
59 attr_list.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
60 self.plugin_name_label.set_attributes(attr_list)
62 self.installed_plugins_model = gtk.ListStore(gobject.TYPE_PYOBJECT,
63 gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
64 self.installed_plugins_treeview.set_model(self.installed_plugins_model)
66 renderer = gtk.CellRendererText()
67 col = gtk.TreeViewColumn(_('Plugin'), renderer, text=1)
68 self.installed_plugins_treeview.append_column(col)
70 renderer = gtk.CellRendererToggle()
71 renderer.set_property('activatable', True)
72 renderer.connect('toggled', self.installed_plugins_toggled_cb)
73 col = gtk.TreeViewColumn(_('Active'), renderer, active=2)
74 self.installed_plugins_treeview.append_column(col)
76 # connect signal for selection change
77 selection = self.installed_plugins_treeview.get_selection()
78 selection.connect('changed',
79 self.installed_plugins_treeview_selection_changed)
80 selection.set_mode(gtk.SELECTION_SINGLE)
82 self._clear_installed_plugin_info()
84 self.fill_installed_plugins_model()
86 self.xml.connect_signals(self)
88 self.plugins_notebook.set_current_page(0)
90 self.window.show_all()
91 gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
93 @log_calls('PluginsWindow')
94 def installed_plugins_treeview_selection_changed(self, treeview_selection):
95 model, iter = treeview_selection.get_selected()
96 if iter:
97 plugin = model.get_value(iter, 0)
98 plugin_name = model.get_value(iter, 1)
99 is_active = model.get_value(iter, 2)
101 self._display_installed_plugin_info(plugin)
102 else:
103 self._clear_installed_plugin_info()
105 def _display_installed_plugin_info(self, plugin):
106 self.plugin_name_label.set_text(plugin.name)
107 self.plugin_version_label.set_text(plugin.version)
108 self.plugin_authors_label.set_text(plugin.authors)
109 label = self.plugin_homepage_linkbutton.get_children()[0]
110 label.set_ellipsize(pango.ELLIPSIZE_END)
111 self.plugin_homepage_linkbutton.set_uri(plugin.homepage)
112 self.plugin_homepage_linkbutton.set_label(plugin.homepage)
113 self.plugin_homepage_linkbutton.set_property('sensitive', True)
115 desc_textbuffer = self.plugin_description_textview.get_buffer()
116 desc_textbuffer.set_text(plugin.description)
117 self.plugin_description_textview.set_property('sensitive', True)
118 self.uninstall_plugin_button.set_property('sensitive',
119 gajim.PLUGINS_DIRS[1] in plugin.__path__)
120 if plugin.config_dialog is None:
121 self.configure_plugin_button.set_property('sensitive', False)
122 else:
123 self.configure_plugin_button.set_property('sensitive', True)
125 def _clear_installed_plugin_info(self):
126 self.plugin_name_label.set_text('')
127 self.plugin_version_label.set_text('')
128 self.plugin_authors_label.set_text('')
129 self.plugin_homepage_linkbutton.set_uri('')
130 self.plugin_homepage_linkbutton.set_label('')
131 self.plugin_homepage_linkbutton.set_property('sensitive', False)
133 desc_textbuffer = self.plugin_description_textview.get_buffer()
134 desc_textbuffer.set_text('')
135 self.plugin_description_textview.set_property('sensitive', False)
136 self.uninstall_plugin_button.set_property('sensitive', False)
137 self.configure_plugin_button.set_property('sensitive', False)
139 @log_calls('PluginsWindow')
140 def fill_installed_plugins_model(self):
141 pm = gajim.plugin_manager
142 self.installed_plugins_model.clear()
143 self.installed_plugins_model.set_sort_column_id(1, gtk.SORT_ASCENDING)
145 for plugin in pm.plugins:
146 self.installed_plugins_model.append([plugin, plugin.name,
147 plugin.active])
149 @log_calls('PluginsWindow')
150 def installed_plugins_toggled_cb(self, cell, path):
151 is_active = self.installed_plugins_model[path][2]
152 plugin = self.installed_plugins_model[path][0]
154 if is_active:
155 gajim.plugin_manager.deactivate_plugin(plugin)
156 else:
157 try:
158 gajim.plugin_manager.activate_plugin(plugin)
159 except GajimPluginActivateException, e:
160 WarningDialog(_('Plugin failed'), str(e))
161 return
163 self.installed_plugins_model[path][2] = not is_active
165 @log_calls('PluginsWindow')
166 def on_plugins_window_destroy(self, widget):
167 '''Close window'''
168 del gajim.interface.instances['plugins']
170 @log_calls('PluginsWindow')
171 def on_close_button_clicked(self, widget):
172 self.window.destroy()
174 @log_calls('PluginsWindow')
175 def on_configure_plugin_button_clicked(self, widget):
176 #log.debug('widget: %s'%(widget))
177 selection = self.installed_plugins_treeview.get_selection()
178 model, iter = selection.get_selected()
179 if iter:
180 plugin = model.get_value(iter, 0)
181 plugin_name = model.get_value(iter, 1)
182 is_active = model.get_value(iter, 2)
185 result = plugin.config_dialog.run(self.window)
187 else:
188 # No plugin selected. this should never be reached. As configure
189 # plugin button should only be clickable when plugin is selected.
190 # XXX: maybe throw exception here?
191 pass
193 @log_calls('PluginsWindow')
194 def on_uninstall_plugin_button_clicked(self, widget):
195 selection = self.installed_plugins_treeview.get_selection()
196 model, iter = selection.get_selected()
197 if iter:
198 plugin = model.get_value(iter, 0)
199 plugin_name = model.get_value(iter, 1).decode('utf-8')
200 is_active = model.get_value(iter, 2)
201 try:
202 gajim.plugin_manager.remove_plugin(plugin)
203 except PluginsystemError, e:
204 WarningDialog(_('Unable to properly remove the plugin'),
205 str(e), self.window)
206 return
207 model.remove(iter)
209 @log_calls('PluginsWindow')
210 def on_install_plugin_button_clicked(self, widget):
211 def show_warn_dialog():
212 text = _('Archive is malformed')
213 dialog = WarningDialog(text, '', transient_for=self.window)
214 dialog.set_modal(False)
215 dialog.popup()
217 def _on_plugin_exists(zip_filename):
218 def on_yes(is_checked):
219 plugin = gajim.plugin_manager.install_from_zip(zip_filename,
220 True)
221 if not plugin:
222 show_warn_dialog()
223 return
224 model = self.installed_plugins_model
226 for row in xrange(len(model)):
227 if plugin == model[row][0]:
228 model.remove(model.get_iter((row, 0)))
229 break
231 iter_ = model.append([plugin, plugin.name, False])
232 sel = self.installed_plugins_treeview.get_selection()
233 sel.select_iter(iter_)
235 YesNoDialog(_('Plugin already exists'), sectext=_('Overwrite?'),
236 on_response_yes=on_yes)
238 def _try_install(zip_filename):
239 try:
240 plugin = gajim.plugin_manager.install_from_zip(zip_filename)
241 except PluginsystemError, er_type:
242 error_text = str(er_type)
243 if error_text == _('Plugin already exists'):
244 _on_plugin_exists(zip_filename)
245 return
247 WarningDialog(error_text, '"%s"' % zip_filename, self.window)
248 return
249 if not plugin:
250 show_warn_dialog()
251 return
252 model = self.installed_plugins_model
253 iter_ = model.append([plugin, plugin.name, False])
254 sel = self.installed_plugins_treeview.get_selection()
255 sel.select_iter(iter_)
257 self.dialog = ArchiveChooserDialog(on_response_ok=_try_install)
260 class GajimPluginConfigDialog(gtk.Dialog):
262 @log_calls('GajimPluginConfigDialog')
263 def __init__(self, plugin, **kwargs):
264 gtk.Dialog.__init__(self, '%s %s'%(plugin.name, _('Configuration')),
265 **kwargs)
266 self.plugin = plugin
267 self.add_button('gtk-close', gtk.RESPONSE_CLOSE)
269 self.child.set_spacing(3)
271 self.init()
273 @log_calls('GajimPluginConfigDialog')
274 def run(self, parent=None):
275 self.set_transient_for(parent)
276 self.on_run()
277 self.show_all()
278 result = super(GajimPluginConfigDialog, self).run()
279 self.hide()
280 return result
282 def init(self):
283 pass
285 def on_run(self):
286 pass