1
2 __docformat__ = "restructuredtext"
3 import mrv.maya.ui as ui
4 from mrv.maya.util import (logException,)
5
6 from control import FinderElement
7
8 from util import concat_url
9
10 __all__ = ('Finder', )
11
12 -class Finder(ui.EventSenderUI):
13 """The Finder control implements a finder-like browser, which displays URLs.
14 URLs consist of items separated by the "/" character. Whenever a item is selected,
15 an iProvider compatible instance will be asked for the subitems of the corresponding URL.
16 Using these, a new field will be set up for presentation.
17 A filter can be installed to prevent items from being shown.
18
19 An added benefit is the ability to automatically match previously selected path
20 items on a certain level of the URL with the available ones, allowing to quickly
21 parse through URLs with a similar structure.
22
23 A limitation of the current implementation is, that you can only keep one
24 item selected at once in each url item area."""
25
26
27 t_element = FinderElement
28
29
30
31
32
33 selection_changed = ui.Signal()
34
35
36 url_changed = ui.Signal()
37
38
39
40 - def __init__(self, provider=None, filter=None):
50
51
52
54 """:return: the finder's main layout which contains all controls"""
55 return self._form
56
58 """:return: current url provider"""
59 return self._provider
60
62 """:return: string representing the currently selected, / separated URL, or
63 None if there is no url selected
64 :param absolute: if True, an absolute URL will be provided using the provider's
65 root"""
66 items = list()
67 for elm in self._form.listChildren():
68 if not elm.p_manage:
69 break
70 sel_item = elm.selectedUnformattedItem()
71 if sel_item is not None:
72 items.append(sel_item)
73 else:
74 break
75
76
77 url = "/".join(items) or None
78 if absolute and url is not None:
79 url = concat_url(self.provider().root(), url)
80
81 return url
82
84 """:return: number of url elements that are currently shown. A url of 1/2 would
85 have two url elements"""
86 return len(tuple(c for c in self._form.listChildren() if c.p_manage))
87
89 """:return: The selected url item at the given element index or None if nothing
90 is selected
91 :param index: 0 to numUrlElements()-1
92 :raies IndexError:"""
93 return self._form.listChildren()[index].selectedUnformattedItem()
94
96 """:return: list of item ids which are currently being shown
97 :param index: 0 based element index to numUrlElements()-1
98 :raise IndexError:"""
99 return list(self._form.listChildren()[index].base_items)
100
101
102
103
104
105
107 """Set or unset a filter. All items will be sent through the filter, and will
108 be shown only if they pass.
109 :param filter: Functor called f(url,t) and returns True for each item which may
110 be shown in the Finder. The url is the full relative url leading to, but
111 excluding the item t, whose visibility is being decided upon"""
112 self._filter = filter
113
129
135
149
150 - def setUrl(self, url, require_all_items=True, allow_memory=False):
151 """Set the given url to be selected
152 :param url: / separated relative url. The individual items must be available
153 in the provider.
154 :parm require_all_items: if False, the control will display as many items as possible.
155 Otherwise it must display all given items, or raise ValueError
156 :param allow_memory: if true, provider memory may be used to show the longest chosen url,
157 being possibly more than you specify. Currently not implemented"""
158 assert self.provider() is not None, "Provider is not set"
159 cur_url = self.selectedUrl()
160 if cur_url == url:
161 return
162
163
164 for eid, item in enumerate(url.split("/")):
165 elm = self._form.listChildren()[eid]
166 if elm.selectedUnformattedItem() == item:
167 continue
168
169 try:
170 self._set_item_by_index(elm, eid, item)
171 except ValueError:
172 if not require_all_items:
173 break
174
175 self.setUrl(cur_url)
176 raise
177
178
179
180 self.selection_changed.send()
181 self.url_changed.send(self.selectedUrl())
182
183
184
185
186
187
188
189 @logException
200
201
202
203
204
206 """:return: index matching the given item element, which must be one of our children"""
207 assert '|' in element
208 for cid, c in enumerate(self._form.listChildren()):
209 if c == element:
210 return cid
211
212 raise ValueError("Didn't find element: %s" % element)
213
215 """Fill the items from the start_elm_id throughout to all elements, until
216 one url does not yield any items, or the item cannot be selected
217 :param elements: a full list of all available child elements."""
218
219
220 root_url = "/".join(c.selectedUnformattedItem() for c in elements[:start_elm_id])
221
222 manage = True
223 for elm_id in range(start_elm_id, len(elements)):
224
225
226 elm = elements[elm_id]
227 elm.p_manage=manage
228
229 if not manage:
230 continue
231
232
233 items = self.provider().urlItems(root_url)
234 elm.base_items = items
235 if not items:
236
237 if len(elements) > 1:
238 elm.p_manage=False
239 manage=False
240 continue
241
242
243 if elm.p_numberOfItems:
244 elm.p_removeAll = True
245
246
247 for item in items:
248 elm.p_append = self.provider().formatItem(root_url, elm_id, item)
249
250
251
252 sel_item = self.provider().storedUrlItemByIndex(elm_id)
253 if sel_item is None:
254
255 manage=False
256 continue
257
258
259 try:
260 elm.selectUnformattedItem(sel_item)
261 except (RuntimeError, ValueError):
262 manage=False
263 continue
264
265
266
267 if root_url:
268 root_url += "/"
269
270 root_url += sel_item
271
272
273
275 """Possibly create and fill the given element index, all following elements
276 are set invivisble"""
277 children = self._form.listChildren()
278
279
280 elms_to_create = max(0, (index+1) - len(children))
281 if elms_to_create:
282 self._form.setActive()
283 for i in range(elms_to_create):
284
285 child = self._form.add(self.t_element(allowMultiSelection=False, font="smallFixedWidthFont"))
286 children.append(child)
287
288 child.e_selectCommand = self._element_selection_changed
289
290 t, b, l, r = self._form.kSides
291 m = 2
292
293
294 self._form.setup( attachForm=((child, t, m), (child, b, m)),
295 attachNone=(child, r) )
296
297
298 if len(children) == 1:
299
300 self._form.setup(attachForm=(child, l, m))
301 else:
302
303 self._form.setup(attachControl=(child, l, m, children[-2]))
304
305
306
307
308
309 self._set_element_items(index, children)
310
311
312