~ubuntu-branches/ubuntu/trusty/pitivi/trusty

« back to all changes in this revision

Viewing changes to pitivi/ui/pluginmanagerdialog.py

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-07-07 13:43:47 UTC
  • mto: (6.1.9 sid) (1.2.12)
  • mto: This revision was merged to the branch mainline in revision 32.
  • Revision ID: james.westby@ubuntu.com-20110707134347-cari9kxjiakzej9z
Tags: upstream-0.14.1
ImportĀ upstreamĀ versionĀ 0.14.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# PiTiVi , Non-linear video editor
2
 
#
3
 
#       pitivi/ui/pluginmanagerdialog.py
4
 
#
5
 
# Copyright (c) 2007, Luca Della Santina <dellasantina@farm.unipi.it>
6
 
#
7
 
# This program is free software; you can redistribute it and/or
8
 
# modify it under the terms of the GNU Lesser General Public
9
 
# License as published by the Free Software Foundation; either
10
 
# version 2.1 of the License, or (at your option) any later version.
11
 
#
12
 
# This program is distributed in the hope that it will be useful,
13
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
# Lesser General Public License for more details.
16
 
#
17
 
# You should have received a copy of the GNU Lesser General Public
18
 
# License along with this program; if not, write to the
19
 
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
 
# Boston, MA 02111-1307, USA.
21
 
 
22
 
import os
23
 
import gtk
24
 
import gtk.glade
25
 
import pango
26
 
import gobject
27
 
from gettext import gettext as _
28
 
 
29
 
from pitivi.configure import LIBDIR
30
 
import pitivi.plugincore as plugincore
31
 
import pitivi.pluginmanager as pluginmanager
32
 
 
33
 
(COL_ENABLED, COL_INFO, COL_CATEGORY, COL_PLUGIN) = range(4)
34
 
(RESPONSE_ABOUT, RESPONSE_CONFIGURE, RESPONSE_DELETE) = range(3)
35
 
 
36
 
class PluginManagerDialog(object):
37
 
    """ This dialog is the main way user can interact with the plugin manager.
38
 
        It allows to install,remove,update,configure and enable plugins. """
39
 
 
40
 
    def __init__(self, plugin_manager):
41
 
        self.pm = plugin_manager
42
 
 
43
 
        # load user interface items
44
 
        if 'pitivi.exe' in __file__.lower():
45
 
            glade_dir = LIBDIR
46
 
        else:
47
 
            glade_dir = os.path.dirname(os.path.abspath(__file__))
48
 
        self.wTree = gtk.glade.XML(os.path.join(glade_dir, 'pluginmanagerdialog.glade'))
49
 
        self.window = self.wTree.get_widget('pluginmanager_dlg')
50
 
        self.search_entry = self.wTree.get_widget('search_entry')
51
 
        self.category_cmb = self.wTree.get_widget('category_cmb')
52
 
        self.about_btn = self.wTree.get_widget('about_btn')
53
 
        self.configure_btn = self.wTree.get_widget('configure_btn')
54
 
        self.delete_btn = self.wTree.get_widget('delete_btn')
55
 
        self.plugin_tree = self.wTree.get_widget('plugin_tree')
56
 
        self.search_entry = self.wTree.get_widget('search_entry')
57
 
 
58
 
        # connect signals
59
 
        self.wTree.signal_autoconnect(self)
60
 
 
61
 
        # intialize plugin list
62
 
        self._initialize_plugin_tree(self.plugin_tree)
63
 
        self._initialize_category_cmb(self.category_cmb)
64
 
        self.refresh_category()
65
 
        self.refresh_tree()
66
 
 
67
 
        # show the window
68
 
        self.search_entry.grab_focus()
69
 
        self.window.show()
70
 
 
71
 
    def _initialize_plugin_tree(self, tree):
72
 
        """ Perform treeview initialization """
73
 
 
74
 
        self.model = gtk.ListStore(gobject.TYPE_BOOLEAN,
75
 
                                    gobject.TYPE_STRING,
76
 
                                    gobject.TYPE_STRING,
77
 
                                    object)
78
 
 
79
 
        # init tree view
80
 
        tree.set_model(self.model)
81
 
        tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
82
 
 
83
 
        # Enable Drag&Drop
84
 
        tree.enable_model_drag_dest([("text/uri-list", 0, 1)], \
85
 
                                    gtk.gdk.ACTION_DEFAULT)
86
 
        tree.connect("drag-data-received", self.drag_data_received_cb)
87
 
 
88
 
        # plugin enabled status
89
 
        cell = gtk.CellRendererToggle()
90
 
        cell.set_property('activatable', True)
91
 
        cell.connect('toggled', self.plugin_enabled_cb, self.model)
92
 
 
93
 
        column = gtk.TreeViewColumn(_("Enabled"))
94
 
        tree.append_column(column)
95
 
        column.pack_start(cell, True)
96
 
        column.add_attribute(cell, 'active', COL_ENABLED)
97
 
        column.set_sort_column_id(COL_ENABLED)
98
 
 
99
 
        # plugin name
100
 
        cell = gtk.CellRendererText()
101
 
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
102
 
 
103
 
        column = gtk.TreeViewColumn(_("Plugin"))
104
 
        tree.append_column(column)
105
 
        column.pack_start(cell, True)
106
 
        column.set_min_width(300)
107
 
        column.add_attribute(cell, "markup", COL_INFO)
108
 
        column.set_sort_column_id(COL_INFO)
109
 
 
110
 
        # plugin category
111
 
        cell = gtk.CellRendererText()
112
 
 
113
 
        column = gtk.TreeViewColumn(_("Category"))
114
 
        tree.append_column(column)
115
 
        column.pack_start(cell, False)
116
 
        column.add_attribute(cell, 'text', COL_CATEGORY)
117
 
        column.set_sort_column_id(COL_CATEGORY)
118
 
 
119
 
    def _initialize_category_cmb(self, combo):
120
 
        """ perform category combobox initialization """
121
 
 
122
 
        self.model_category = gtk.ListStore(gobject.TYPE_STRING)
123
 
        combo.set_model(self.model_category)
124
 
 
125
 
    def search_entry_changed_cb(self, widget):
126
 
        """ filter the plugin list according to searched text """
127
 
 
128
 
        self.refresh_tree(self.search_entry.get_text())
129
 
 
130
 
        if self.search_entry.get_text():
131
 
            self.search_entry.modify_base(gtk.STATE_NORMAL,\
132
 
                                            gtk.gdk.color_parse("#FBFAD6"))
133
 
        else:
134
 
            self.search_entry.modify_base(gtk.STATE_NORMAL, None)
135
 
 
136
 
    def category_cmb_changed_cb(self, widget):
137
 
        """ Catch changes in category combobox triggered by the user """
138
 
 
139
 
        self.refresh_tree(self.search_entry.get_text())
140
 
 
141
 
    def refresh_tree(self, filter_text = None):
142
 
        """
143
 
        Refresh the list of plugins according to filter_text
144
 
 
145
 
        @param filter_text: plugin name must have this substring (case insensitive)
146
 
        """
147
 
 
148
 
        def _get_active_category():
149
 
            """ return the active category the chosen from the combobox """
150
 
            if self.category_cmb.get_active() > 0:
151
 
                return self.model_category[self.category_cmb.get_active()][0]
152
 
            else:
153
 
                return None
154
 
 
155
 
        self.model.clear()
156
 
 
157
 
        for plugin in self.pm.getPlugins(category=_get_active_category()):
158
 
            if filter_text and (plugin.name.lower().find(filter_text.lower()) < 0):
159
 
                continue
160
 
 
161
 
            rowiter = self.model.append()
162
 
            self.model.set_value(rowiter, COL_ENABLED, plugin.enabled)
163
 
            self.model.set_value(rowiter, COL_INFO, "<b>%s</b>\n%s"\
164
 
                                            %(plugin.name, plugin.description))
165
 
            self.model.set_value(rowiter, COL_CATEGORY, plugin.category)
166
 
            self.model.set_value(rowiter, COL_PLUGIN, plugin)
167
 
 
168
 
        # refresh available operations according to the new visualized list
169
 
        self.plugin_tree_button_release_cb(self.plugin_tree, None)
170
 
 
171
 
    def refresh_category(self):
172
 
        """ Refresh the list of plugin categories """
173
 
        self._initialize_category_cmb(self.category_cmb)
174
 
 
175
 
        # The first entry is always "All categories"
176
 
        rowiter = self.model_category.append()
177
 
        self.model_category.set_value(rowiter, 0, _("All categories"))
178
 
 
179
 
        categories = []
180
 
        # populate categories
181
 
        for plugin in self.pm.getPlugins():
182
 
            if not plugin.category in categories:
183
 
                categories.append(plugin.category)
184
 
 
185
 
        #populate combo model with categories
186
 
        for category in categories:
187
 
            rowiter = self.model_category.append()
188
 
            self.model_category.set_value(rowiter, 0, category)
189
 
 
190
 
        self.category_cmb.set_active(0)
191
 
 
192
 
    def response_cb(self, widget, response):
193
 
        """ Catch signal emitted by user-pressed buttons in the main bar """
194
 
        if response == gtk.RESPONSE_DELETE_EVENT:
195
 
            self.window.destroy()
196
 
        elif response == gtk.RESPONSE_CLOSE:
197
 
            self.window.destroy()
198
 
        elif response == RESPONSE_ABOUT:
199
 
            self.show_plugin_info()
200
 
        elif response == RESPONSE_CONFIGURE:
201
 
            for plugin in self._get_selected_plugins():
202
 
                plugin.configure()
203
 
        elif response == RESPONSE_DELETE:
204
 
            self.uninstall_selected_plugins()
205
 
 
206
 
    def plugin_enabled_cb(self, cell, path, model):
207
 
        """ Toggle loaded status for selected plugin"""
208
 
 
209
 
        model[path][COL_ENABLED] = model[path][COL_PLUGIN].enabled = not model[path][COL_PLUGIN].enabled
210
 
 
211
 
    def plugin_tree_button_release_cb(self, widget, event):
212
 
        """ Select plugins from the list """
213
 
 
214
 
        selection = widget.get_selection()
215
 
        if not selection:
216
 
            return
217
 
 
218
 
        if selection.count_selected_rows() == 1:
219
 
            self.about_btn.set_sensitive(True)
220
 
 
221
 
            (model, pathlist) = selection.get_selected_rows()
222
 
            row = model.get_iter(pathlist[0])
223
 
            plugin = model[row][COL_PLUGIN]
224
 
            self.configure_btn.set_sensitive(plugincore.IConfigurable.providedBy(plugin))
225
 
            self.delete_btn.set_sensitive(self.pm.canUninstall(plugin))
226
 
        elif selection.count_selected_rows() > 1:
227
 
            self.about_btn.set_sensitive(False)
228
 
            self.configure_btn.set_sensitive(False)
229
 
            self.delete_btn.set_sensitive(True)
230
 
        else:
231
 
            self.about_btn.set_sensitive(False)
232
 
            self.configure_btn.set_sensitive(False)
233
 
            self.delete_btn.set_sensitive(False)
234
 
 
235
 
    def _get_selected_plugins(self):
236
 
        """
237
 
        Retrieve from treeview widget those plugins selected by the use
238
 
 
239
 
        @return: the list of plugins selected by the user
240
 
        """
241
 
 
242
 
        selection = self.plugin_tree.get_selection()
243
 
        if not selection:
244
 
            return []
245
 
 
246
 
        (model, pathlist) = selection.get_selected_rows()
247
 
        sel_plugins = []
248
 
        for path in pathlist:
249
 
            row = model.get_iter(path)
250
 
            sel_plugins.append(model[row][COL_PLUGIN])
251
 
 
252
 
        return sel_plugins
253
 
 
254
 
    def show_plugin_info(self):
255
 
        """ Show the about dialog for selected plugins """
256
 
 
257
 
        for plugin in self._get_selected_plugins():
258
 
            dialog = gtk.AboutDialog()
259
 
            dialog.connect("response", lambda x, y: dialog.destroy())
260
 
            dialog.set_name(plugin.name)
261
 
            dialog.set_version(plugin.version)
262
 
            dialog.set_authors(plugin.authors.split(","))
263
 
            dialog.set_comments(plugin.description)
264
 
            dialog.show()
265
 
 
266
 
    def uninstall_selected_plugins(self):
267
 
        """ Uninstall plugins selected by the user """
268
 
 
269
 
        # ensure the user really wants this operation to be performed
270
 
        dialog = gtk.MessageDialog(
271
 
            parent = self.window,
272
 
            flags = gtk.DIALOG_MODAL,
273
 
            type = gtk.MESSAGE_WARNING,
274
 
            buttons = gtk.BUTTONS_OK_CANCEL,
275
 
            message_format = _("Are you sure you want to remove the selected plugins?"))
276
 
        dialog.set_title(_("Confirm remove operation"))
277
 
        try:
278
 
            if dialog.run() == gtk.RESPONSE_CANCEL:
279
 
                return
280
 
        finally:
281
 
            dialog.destroy()
282
 
 
283
 
        # remove selected plugins
284
 
        for plugin in self._get_selected_plugins():
285
 
            try:
286
 
                self.pm.uninstall(plugin)
287
 
            except Exception, e:
288
 
                error_dialog = gtk.MessageDialog(
289
 
                    parent = self.window,
290
 
                    flags = gtk.DIALOG_MODAL,
291
 
                    type = gtk.MESSAGE_ERROR,
292
 
                    buttons = gtk.BUTTONS_CLOSE,
293
 
                    message_format = _("Cannot remove %s") % (plugin.name))
294
 
                error_dialog.run()
295
 
                error_dialog.destroy()
296
 
 
297
 
        # refresh the plugin list
298
 
        self.pm.collect()
299
 
        self.refresh_tree()
300
 
        self.refresh_category()
301
 
 
302
 
    def drag_data_received_cb(self, widget, context, x, y, selection,
303
 
                            targetType, time):
304
 
        """ handle drag&drop of new plugins into the list by installing them"""
305
 
 
306
 
        uri_list = selection.data.strip().split()
307
 
        installed = False
308
 
 
309
 
        for uri in uri_list:
310
 
            # ensure a file is dragged
311
 
            if not (uri.startswith("file://") and os.path.isfile(uri[7:])):
312
 
                continue
313
 
 
314
 
            filename = uri[7:]
315
 
            try:
316
 
                self.pm.install(filename, self.pm.local_plugin_path)
317
 
                installed = True
318
 
            except plugincore.DuplicatePluginError, e:
319
 
                # Plugin already exists, ask the user if he wants to update
320
 
                dialog = gtk.MessageDialog(
321
 
                    parent = self.window,
322
 
                    flags = gtk.DIALOG_MODAL,
323
 
                    type = gtk.MESSAGE_WARNING,
324
 
                    buttons = gtk.BUTTONS_OK_CANCEL,
325
 
                    message_format = _("Update the existing plugin?"))
326
 
 
327
 
                dialog.format_secondary_text(
328
 
                    _("This plugin is already installed in your system.\nIf you agree, version %(v1)s will be replaced with version %(v2)s")\
329
 
                    %{'v1': e.old_plugin.version, 'v2': e.new_plugin.version})
330
 
 
331
 
                dialog.set_title(_("Duplicate plugin found"))
332
 
                try:
333
 
                    if dialog.run() == gtk.RESPONSE_OK:
334
 
                        self.pm.update(filename, self.pm.local_plugin_path)
335
 
                        installed = True
336
 
                finally:
337
 
                    dialog.destroy()
338
 
            except plugincore.InvalidPluginError, e:
339
 
                # The file user is trying to install is not a valid plugin
340
 
                error_dialog = gtk.MessageDialog(
341
 
                    parent = self.window,
342
 
                    flags = gtk.DIALOG_MODAL,
343
 
                    type = gtk.MESSAGE_ERROR,
344
 
                    buttons = gtk.BUTTONS_CLOSE,
345
 
                    message_format = _("Cannot install %s\nThe file is not a valid plugin") % e.filename)
346
 
                error_dialog.run()
347
 
                error_dialog.destroy()
348
 
 
349
 
        if installed:
350
 
            # refresh plugin list if the operation succedded
351
 
            self.pm.collect()
352
 
            self.refresh_tree()
353
 
            self.refresh_category()
354
 
            # Tell the drag source that operation succedded
355
 
            context.finish(success=True, del_=False, time=time)
356
 
 
357
 
if __name__ == "__main__":
358
 
    pm = pluginmanager.PluginManager("./plugins", "./plugins-settings")
359
 
    PluginManagerDialog(pm)
360
 
    gtk.main()