source: orange/Orange/OrangeCanvas/registry/base.py @ 11252:e50ca88b9854

Revision 11252:e50ca88b9854, 5.4 KB checked in by Ales Erjavec <ales.erjavec@…>, 16 months ago (diff)

Changes to widget descriptors for better documentation/help.

Line 
1"""
2WidgetRegistry Base
3
4"""
5
6import logging
7import bisect
8
9from operator import attrgetter
10
11from . import description
12
13log = logging.getLogger(__name__)
14
15# Registry hex version
16VERSION_HEX = 0x000101
17
18
19class WidgetRegistry(object):
20    """A container for widget and category descriptions.
21
22    This class is most often used with WidgetDiscovery class but can
23    be used separately.
24
25    >>> reg = WidgetRegistry()
26    >>> file_desc = description.WidgetDescription.from_module(
27    ...     "Orange.OrangeWidgets.Data.OWFile"
28    ... )
29    ...
30    >>> reg.register_widget(file_desc)
31    >>> reg.widgets()
32    [...
33
34    """
35
36    def __init__(self, other=None):
37        # A list of (category, widgets_list) tuples ordered by priority.
38        self.registry = []
39        # tuples from 'registry' indexed by name
40        self._categories_dict = {}
41        # WidgetDscriptions by qualified name
42        self._widgets_dict = {}
43
44        if other is not None:
45            if not isinstance(other, WidgetRegistry):
46                raise TypeError("Expected a 'WidgetRegistry' got %r." \
47                                % type(other).__name__)
48
49            self.registry = list(other.registry)
50            self._categories_dict = dict(other._categories_dict)
51            self._widgets_dict = dict(other._widgets_dict)
52
53    def categories(self):
54        """List all top level widget categories ordered by priority.
55        """
56        return [c for c, _ in self.registry]
57
58    def category(self, name):
59        """Return category with `name`.
60
61        .. note:: Categories are identified by `name` attribute in contrast
62            with widgets which are identified by `qualified_name`.
63
64        """
65        return self._categories_dict[name][0]
66
67    def has_category(self, name):
68        """Does the category with `name` exist in this registry.
69        """
70        return name in self._categories_dict
71
72    def widgets(self, category=None):
73        """List all widgets in a `category`. If no category is
74        specified list widgets in all categories.
75
76        """
77        if category is None:
78            categories = self.categories()
79        elif isinstance(category, basestring):
80            categories = [self.category(category)]
81        else:
82            categories = [category]
83
84        widgets = []
85        for cat in categories:
86            if isinstance(cat, basestring):
87                cat = self.category(cat)
88            cat_widgets = self._categories_dict[cat.name][1]
89            widgets.extend(sorted(cat_widgets,
90                                  key=attrgetter("priority")))
91        return widgets
92
93    def widget(self, qualified_name):
94        """Return widget description for `qualified_name`.
95        Raise KeyError if the description does not exist.
96
97        """
98        return self._widgets_dict[qualified_name]
99
100    def has_widget(self, qualified_name):
101        """Does the widget with `qualified_name` exist in this registry.
102        """
103        return qualified_name in self._widgets_dict
104
105    def register_widget(self, desc):
106        """Register a widget by its description.
107        """
108        if not isinstance(desc, description.WidgetDescription):
109            raise TypeError("Expected a 'WidgetDescription' got %r." \
110                            % type(desc).__name__)
111
112        if self.has_widget(desc.qualified_name):
113            raise ValueError("%r already exists in the registry." \
114                             % desc.qualified_name)
115
116        category = desc.category
117        if category is None:
118            category = "Unspecified"
119
120        if self.has_category(category):
121            cat_desc = self.category(category)
122        else:
123            log.warning("Creating a default category %r.", category)
124            cat_desc = description.CategoryDescription(name=category)
125            self.register_category(cat_desc)
126
127        self._insert_widget(cat_desc, desc)
128
129    def register_category(self, desc):
130        """Register category by its description.
131
132        .. note:: It is always best to register the category
133            before the widgets belonging to it.
134
135        """
136        if not isinstance(desc, description.CategoryDescription):
137            raise TypeError("Expected a 'CategoryDescription' got %r." \
138                            % type(desc).__name__)
139
140        name = desc.name
141        if not name:
142            log.warning("Creating a default category name.")
143            name = "default"
144
145        if any(name == c.name for c in self.categories()):
146            log.warning("A category with %r name already exists" % name)
147            return
148
149        self._insert_category(desc)
150
151    def _insert_category(self, desc):
152        """Insert category description into 'registry' list
153        """
154        priority = desc.priority
155        priorities = [c.priority for c, _ in self.registry]
156        insertion_i = bisect.bisect_right(priorities, priority)
157
158        item = (desc, [])
159        self.registry.insert(insertion_i, item)
160        self._categories_dict[desc.name] = item
161
162    def _insert_widget(self, category, desc):
163        """Insert widget description `desc` into `category`.
164        """
165        assert(isinstance(category, description.CategoryDescription))
166        _, widgets = self._categories_dict[category.name]
167
168        priority = desc.priority
169        priorities = [w.priority for w in widgets]
170        insertion_i = bisect.bisect_right(priorities, priority)
171        widgets.insert(insertion_i, desc)
172        self._widgets_dict[desc.qualified_name] = desc
Note: See TracBrowser for help on using the repository browser.