summaryrefslogtreecommitdiff
path: root/kberylsettings/plugindialog.py
blob: 0dd5a6b95541a54dd2858030f564874446072bbf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" kberylsettings.plugindialog -> defines a dialog box for selecting plugins.

Tried to use KActionSelector instead of KListView, but it didn't make
much sense.
"""
from kdecore import KIcon, i18n
from kdeui import KDialogBase, KListView, KMessageBox
from qt import QCheckListItem, QLabel

from kberylsettings.lib import Signals, iconLoader
from kberylsettings.widget import ListView

class PluginList(ListView):
    """ PluginList -> list view for the select plugins dialog

    """
    def __init__(self, parent):
        ListView.__init__(self, parent)
        self.addColumn(i18n('Plugin'))
        self.addColumn(i18n('Categories'))
        self.addColumn(i18n('Description'))
        self.setSorting(self.columns()+1)
        
    def addPlugins(self, context, stateMap):
        """ creates list view items from plugins in context

        @param context berylsetting Context instance
        @return mapping of plugin names and their enabled state
        """
        count = textlen = 0
        loader = iconLoader()
        cats = context.categories
        
        for p in context.plugins[::-1]:
            item = QCheckListItem(self, p.ShortDesc, QCheckListItem.CheckBox)
            item.setEnabled(not p.isGeneral)
            cnames = str.join(',', [c.ShortDesc for c in cats if p in c.Plugins])
            item.setText(1, cnames)
            item.setText(2, p.LongDesc)
            item.setPixmap(0, p.icon(KIcon.SizeSmall, loader))
            if p.Enabled:
                stateMap[p.Name] = True
                item.setState(QCheckListItem.On)
            else:
                stateMap[p.Name] = False
            count += 1
            textlen = max(textlen, len(p.ShortDesc + p.LongDesc))

        self.adjustMinSize(count, textlen)
        return stateMap

    def adjustMinSize(self, count, maxlen):
        """ adjusts minimum size based on child count and text length

        @param count number of items
        @param maxlen maximum length of item text (all columns)
        @return None
        """
        height = count * self.fontMetrics().height()
        self.setMinimumHeight(height * 0.5)
        width = maxlen * self.fontMetrics().maxWidth() * 0.2
        self.setMinimumWidth(width)


class PluginDialog(KDialogBase):
    """ PluginDialog -> a dialog for enabling and disabling plugins

    """
    def __init__(self, parent, context, mapping):
        KDialogBase.__init__(self, parent, '', True, i18n('Select Plugins'),
                             KDialogBase.Ok|KDialogBase.Cancel)
        self.context = context        
        main = self.makeVBoxMainWidget()
        self.label = QLabel('Enable or disable plugins below.', main)
        self.listView = PluginList(main)
        self.connect(self.listView, Signals.itemClicked, self.changePlugin)
        self.pluginMap = self.listView.addPlugins(context, mapping)

    def changePlugin(self, item):
        """ handle a possible change to the plugins checkbox

        @param item QCheckListItem instance
        @return None
        """
        if not item:
            return
        plugin = self.context.plugin(item.text(0))
        state = item.state()        
        if state == item.On:
            self.pluginMap[plugin.Name] = True
            self.satisfy(plugin)
        elif state == item.Off:
            remaining = self.needs(plugin)
            if remaining:
                item.setState(item.On)                
                text = 'Cannot remove plugin "%s" required by %s.'
                need = ['"%s"' % r.ShortDesc for r in remaining]
                text %= (plugin.ShortDesc, str.join(', ', need))
                KMessageBox.sorry(self, text)
            else:
                self.pluginMap[plugin.Name] = False

    def satisfy(self, plugin):
        """ enable requirement for plugin if necessary

        @param plugin berylsettings Plugin instance
        @return None
        """
        for requirement in plugin.Requires:
            for p in self.context.plugins:
                if requirement in p.Provides:
                    if not self.pluginMap[p.Name]:
                        self.pluginMap[p.Name] = True
                        item = self.listView.findItem(p.ShortDesc, 0)
                        if item:
                            item.setState(item.On)
                        for req in p.Requires:
                            self.satisfy(p)

    def needs(self, plugin):
        """ check that all requirements for plugin are met

        @param plugin berylsettings Plugin instance
        @return sequence of required plugins
        """
        pending = self.pending(plugin)
        allProvided = []            
        for p in pending:
            allProvided.extend(p.Provides)
        notMet = []
        for p in pending:
            for req in p.Requires:
                if req not in allProvided:
                    notMet.append(p)
        return notMet

    def pending(self, exclude):
        """ generates a sequence of enabled plugins, based on current selections

        @param exclude plugin to exclude from returned list
        @return list of berylsetting Plugin instances
        """
        names = [name for name, enabled in self.pluginMap.items() if enabled]
        return [self.context.plugin(n) for n in names if n != exclude.Name]