| Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
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', )
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 #{ Configuration
27 t_element = FinderElement
28 #} END configuration
29
30 #{ Signals
31
32 # s()
33 selection_changed = ui.Signal()
34
35 # s(url)
36 url_changed = ui.Signal()
37
38 #} END signals
39
41 self._provider = None
42 self._filter = None
43
44 # initialize layouts
45 self._form = ui.FormLayout()
46 self._form.setParentActive()
47
48 self.setProvider(provider)
49 self.setFilter(filter)
50
51 # { Query
52
56
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 # END for each element
76
77 url = "/".join(items) or None
78 if absolute and url is not None:
79 url = concat_url(self.provider().root(), url)
80 # END handle absolute urls
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 #} END Query
103
104 #{ Edit
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
115 """Set the provider to use
116 :param provider: ``iFinderProvider`` compatible instance, or None
117 If no provider is set, the instance will be blank"""
118 if self._provider is provider:
119 return
120 # END early bailout
121 self._provider = provider
122
123 if provider is not None:
124 self._set_element_visible(0)
125 # END handle initial setup
126
127 self.selection_changed.send()
128 self.url_changed.send(self.selectedUrl())
129
131 self._set_element_visible(index)
132 elm.selectUnformattedItem(item)
133 self.provider().storeUrlItem(index, item)
134 self._set_element_visible(index+1)
135
137 """Set the given string item, which sits at the given index of a url
138 :raise ValueError: if item does not exist at given index
139 :raise IndexError: if index is not currently shown"""
140 assert self.provider() is not None, "Provider is not set"
141 elm = self._form.listChildren()[index]
142 if elm.selectedUnformattedItem() == item:
143 return
144 # END early abort if nothing changes
145 self._set_item_by_index(elm, index, item)
146
147 self.selection_changed.send()
148 self.url_changed.send(self.selectedUrl())
149
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 # END ignore similar urls
163
164 for eid, item in enumerate(url.split("/")):
165 elm = self._form.listChildren()[eid]
166 if elm.selectedUnformattedItem() == item:
167 continue
168 # END skip items which already match
169 try:
170 self._set_item_by_index(elm, eid, item)
171 except ValueError:
172 if not require_all_items:
173 break
174 # restore previous url
175 self.setUrl(cur_url)
176 raise
177 # END handle exceptions
178 # END for each item to set
179
180 self.selection_changed.send()
181 self.url_changed.send(self.selectedUrl())
182
183
184
185 #} END edit
186
187 #{ Callbacks
188
189 @logException
191 """Called whenever any element changes its value, which forces the following
192 elements to refresh"""
193 index = self._index_by_item_element(element)
194 # store the currently selected item
195 self.provider().storeUrlItem(index, element.selectedUnformattedItem())
196 self._set_element_visible(index+1)
197
198 self.selection_changed.send()
199 self.url_changed.send(self.selectedUrl())
200
201 #} END callbacks
202
203 #{ Utilities
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 # END for each child to enumerate
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 # obtain the root url
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 # refill the items according to our provider
226 elm = elements[elm_id]
227 elm.p_manage=manage
228
229 if not manage:
230 continue
231 # END abort if we just disable all others
232
233 items = self.provider().urlItems(root_url)
234 elm.base_items = items
235 if not items:
236 # keep one item visible, even though empty, if its the only one
237 if len(elements) > 1:
238 elm.p_manage=False
239 manage=False
240 continue
241 # END skip on first empty url
242
243 if elm.p_numberOfItems:
244 elm.p_removeAll = True
245 # END remove prior to re-append
246
247 for item in items:
248 elm.p_append = self.provider().formatItem(root_url, elm_id, item)
249 # END for each item to append
250
251 # try to reselect the previously selected item
252 sel_item = self.provider().storedUrlItemByIndex(elm_id)
253 if sel_item is None:
254 # make sure next item is not being shown
255 manage=False
256 continue
257 # END handle item memorization
258
259 try:
260 elm.selectUnformattedItem(sel_item)
261 except (RuntimeError, ValueError):
262 manage=False
263 continue
264 # END handle exception
265
266 # update the root
267 if root_url:
268 root_url += "/"
269 # END assure / is not the first character
270 root_url += sel_item
271 # END for each url to handle
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 # create as many new scrollLists as required,
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 # make sure we keep our array uptodate
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 # they are always attached top+bottom
294 self._form.setup( attachForm=((child, t, m), (child, b, m)),
295 attachNone=(child, r) )
296
297 # we generally keep the right side un-attached
298 if len(children) == 1:
299 # first element goes left
300 self._form.setup(attachForm=(child, l, m))
301 else:
302 # all other elements attach to the right side
303 self._form.setup(attachControl=(child, l, m, children[-2]))
304 # END handle amount of children
305 # children.append(child)
306 # END for each element to add
307 # END if elms to create
308
309 self._set_element_items(index, children)
310
311 #} END utilities
312
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Apr 19 18:00:22 2011 | http://epydoc.sourceforge.net |