comparison src/browser/sat_browser/dialog.py @ 679:a90cc8fc9605

merged branch frontends_multi_profiles
author Goffi <goffi@goffi.org>
date Wed, 18 Mar 2015 16:15:18 +0100
parents a8fddccf5b84
children 9877607c719a
comparison
equal deleted inserted replaced
590:1bffc4c244c3 679:a90cc8fc9605
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 from sat.core.log import getLogger 20 from sat.core.log import getLogger
21 log = getLogger(__name__) 21 log = getLogger(__name__)
22
23 from constants import Const as C
22 from sat_frontends.tools.misc import DEFAULT_MUC 24 from sat_frontends.tools.misc import DEFAULT_MUC
25 from sat_frontends.tools import jid
23 26
24 from pyjamas.ui.VerticalPanel import VerticalPanel 27 from pyjamas.ui.VerticalPanel import VerticalPanel
25 from pyjamas.ui.Grid import Grid 28 from pyjamas.ui.Grid import Grid
26 from pyjamas.ui.HorizontalPanel import HorizontalPanel 29 from pyjamas.ui.HorizontalPanel import HorizontalPanel
27 from pyjamas.ui.PopupPanel import PopupPanel 30 from pyjamas.ui.PopupPanel import PopupPanel
35 from pyjamas.ui import HasAlignment 38 from pyjamas.ui import HasAlignment
36 from pyjamas.ui.KeyboardListener import KEY_ESCAPE, KEY_ENTER 39 from pyjamas.ui.KeyboardListener import KEY_ESCAPE, KEY_ENTER
37 from pyjamas.ui.MouseListener import MouseWheelHandler 40 from pyjamas.ui.MouseListener import MouseWheelHandler
38 from pyjamas import Window 41 from pyjamas import Window
39 42
40 import base_panels 43 import base_panel
41 44
42 45
43 # List here the patterns that are not allowed in contact group names 46 # List here the patterns that are not allowed in contact group names
44 FORBIDDEN_PATTERNS_IN_GROUP = () 47 FORBIDDEN_PATTERNS_IN_GROUP = ()
45 48
46 49
50 unicode = str # XXX: pyjama doesn't manage unicode
51
52
47 class RoomChooser(Grid): 53 class RoomChooser(Grid):
48 """Select a room from the rooms you already joined, or create a new one""" 54 """Select a room from the rooms you already joined, or create a new one"""
49 55
50 GENERATE_MUC = "<use random name>" 56 GENERATE_MUC = "<use random name>"
51 57
52 def __init__(self, host, default_room=DEFAULT_MUC): 58 def __init__(self, host, default_room=DEFAULT_MUC):
59 """
60
61 @param host (SatWebFrontend)
62 """
53 Grid.__init__(self, 2, 2, Width='100%') 63 Grid.__init__(self, 2, 2, Width='100%')
54 self.host = host 64 self.host = host
55 65
56 self.new_radio = RadioButton("room", "Discussion room:") 66 self.new_radio = RadioButton("room", "Discussion room:")
57 self.new_radio.setChecked(True) 67 self.new_radio.setChecked(True)
68 self.box.addFocusListener(self) 78 self.box.addFocusListener(self)
69 self.rooms_list.addFocusListener(self) 79 self.rooms_list.addFocusListener(self)
70 80
71 self.exist_radio.setVisible(False) 81 self.exist_radio.setVisible(False)
72 self.rooms_list.setVisible(False) 82 self.rooms_list.setVisible(False)
73 self.setRooms() 83 self.refreshOptions()
84
85 @property
86 def room(self):
87 """Get the room that has been selected or entered by the user
88
89 @return: jid.JID or None to let the backend generate a new name
90 """
91 if self.exist_radio.getChecked():
92 values = self.rooms_list.getSelectedValues()
93 return jid.JID(values[0]) if values else None
94 value = self.box.getText()
95 return None if value in ('', self.GENERATE_MUC) else jid.JID(value)
74 96
75 def onFocus(self, sender): 97 def onFocus(self, sender):
76 if sender == self.rooms_list: 98 if sender == self.rooms_list:
77 self.exist_radio.setChecked(True) 99 self.exist_radio.setChecked(True)
78 elif sender == self.box: 100 elif sender == self.box:
83 def onLostFocus(self, sender): 105 def onLostFocus(self, sender):
84 if sender == self.box: 106 if sender == self.box:
85 if self.box.getText() == "": 107 if self.box.getText() == "":
86 self.box.setText(self.GENERATE_MUC) 108 self.box.setText(self.GENERATE_MUC)
87 109
88 def setRooms(self): 110 def refreshOptions(self):
89 for room in self.host.room_list: 111 """Refresh the already joined room list"""
112 contact_list = self.host.contact_list
113 muc_rooms = contact_list.getSpecials(C.CONTACT_SPECIAL_GROUP)
114 for room in muc_rooms:
90 self.rooms_list.addItem(room.bare) 115 self.rooms_list.addItem(room.bare)
91 if len(self.host.room_list) > 0: 116 if len(muc_rooms) > 0:
92 self.exist_radio.setVisible(True) 117 self.exist_radio.setVisible(True)
93 self.rooms_list.setVisible(True) 118 self.rooms_list.setVisible(True)
94 self.exist_radio.setChecked(True) 119 self.exist_radio.setChecked(True)
95
96 def getRoom(self):
97 if self.exist_radio.getChecked():
98 values = self.rooms_list.getSelectedValues()
99 return "" if values == [] else values[0]
100 value = self.box.getText()
101 return "" if value == self.GENERATE_MUC else value
102 120
103 121
104 class ContactsChooser(VerticalPanel): 122 class ContactsChooser(VerticalPanel):
105 """Select one or several connected contacts""" 123 """Select one or several connected contacts"""
106 124
118 elif len(nb_contact) == 1: 136 elif len(nb_contact) == 1:
119 nb_contact = (nb_contact[0], nb_contact[0]) 137 nb_contact = (nb_contact[0], nb_contact[0])
120 elif nb_contact is not None: 138 elif nb_contact is not None:
121 nb_contact = (nb_contact, nb_contact) 139 nb_contact = (nb_contact, nb_contact)
122 if nb_contact is None: 140 if nb_contact is None:
123 log.warning("Need to select as many contacts as you want") 141 log.debug("Need to select as many contacts as you want")
124 else: 142 else:
125 log.warning("Need to select between %d and %d contacts" % nb_contact) 143 log.debug("Need to select between %d and %d contacts" % nb_contact)
126 self.nb_contact = nb_contact 144 self.nb_contact = nb_contact
127 self.ok_button = ok_button 145 self.ok_button = ok_button
128 VerticalPanel.__init__(self, Width='100%') 146 VerticalPanel.__init__(self, Width='100%')
129 self.contacts_list = ListBox() 147 self.contacts_list = ListBox()
130 self.contacts_list.setMultipleSelect(True) 148 self.contacts_list.setMultipleSelect(True)
131 self.contacts_list.setWidth("95%") 149 self.contacts_list.setWidth("95%")
132 self.contacts_list.addStyleName('contactsChooser') 150 self.contacts_list.addStyleName('contactsChooser')
133 self.contacts_list.addChangeListener(self.onChange) 151 self.contacts_list.addChangeListener(self.onChange)
134 self.add(self.contacts_list) 152 self.add(self.contacts_list)
135 self.setContacts() 153 self.refreshOptions()
136 self.onChange() 154 self.onChange()
155
156 @property
157 def contacts(self):
158 """Return the selected contacts.
159
160 @return: list[jid.JID]
161 """
162 return [jid.JID(contact) for contact in self.contacts_list.getSelectedValues(True)]
137 163
138 def onChange(self, sender=None): 164 def onChange(self, sender=None):
139 if self.ok_button is None: 165 if self.ok_button is None:
140 return 166 return
141 if self.nb_contact: 167 if self.nb_contact:
142 selected = len(self.contacts_list.getSelectedValues(True)) 168 selected = len(self.contacts_list.getSelectedValues(True))
143 if selected >= self.nb_contact[0] and selected <= self.nb_contact[1]: 169 if selected >= self.nb_contact[0] and selected <= self.nb_contact[1]:
144 self.ok_button.setEnabled(True) 170 self.ok_button.setEnabled(True)
145 else: 171 else:
146 self.ok_button.setEnabled(False) 172 self.ok_button.setEnabled(False)
147 173
148 def setContacts(self, selected=[]): 174 def refreshOptions(self, keep_selected=False):
149 """Fill the list with the connected contacts 175 """Fill the list with the connected contacts.
150 @param select: list of the contacts to select by default 176
151 """ 177 @param keep_selected (boolean): if True, keep the current selection
178 """
179 selection = self.contacts if keep_selected else []
152 self.contacts_list.clear() 180 self.contacts_list.clear()
153 contacts = self.host.contact_panel.getConnected(filter_muc=True) 181 contacts = self.host.contact_list.roster_entities_connected
154 self.contacts_list.setVisibleItemCount(10 if len(contacts) > 5 else 5) 182 self.contacts_list.setVisibleItemCount(10 if len(contacts) > 5 else 5)
155 self.contacts_list.addItem("") 183 self.contacts_list.addItem("")
156 for contact in contacts: 184 for contact in contacts:
157 if contact not in [room.bare for room in self.host.room_list]: 185 self.contacts_list.addItem(contact)
158 self.contacts_list.addItem(contact) 186 if selection:
159 self.contacts_list.setItemTextSelection(selected) 187 self.contacts_list.setItemTextSelection([unicode(contact) for contact in selection])
160
161 def getContacts(self):
162 return self.contacts_list.getSelectedValues(True)
163 188
164 189
165 class RoomAndContactsChooser(DialogBox): 190 class RoomAndContactsChooser(DialogBox):
166 """Select a room and some users to invite in""" 191 """Select a room and some users to invite in"""
167 192
180 button_panel.add(Button("Cancel", self.onCancel)) 205 button_panel.add(Button("Cancel", self.onCancel))
181 206
182 self.room_panel = RoomChooser(host, "" if visible == (False, True) else DEFAULT_MUC) 207 self.room_panel = RoomChooser(host, "" if visible == (False, True) else DEFAULT_MUC)
183 self.contact_panel = ContactsChooser(host, nb_contact, ok_button) 208 self.contact_panel = ContactsChooser(host, nb_contact, ok_button)
184 209
185 self.stack_panel = base_panels.ToggleStackPanel(Width="100%") 210 self.stack_panel = base_panel.ToggleStackPanel(Width="100%")
186 self.stack_panel.add(self.room_panel, visible=visible[0]) 211 self.stack_panel.add(self.room_panel, visible=visible[0])
187 self.stack_panel.add(self.contact_panel, visible=visible[1]) 212 self.stack_panel.add(self.contact_panel, visible=visible[1])
188 self.stack_panel.addStackChangeListener(self) 213 self.stack_panel.addStackChangeListener(self)
189 self.onStackChanged(self.stack_panel, 0, visible[0]) 214 self.onStackChanged(self.stack_panel, 0, visible[0])
190 self.onStackChanged(self.stack_panel, 1, visible[1]) 215 self.onStackChanged(self.stack_panel, 1, visible[1])
196 221
197 self.setWidget(main_panel) 222 self.setWidget(main_panel)
198 self.setHTML(title) 223 self.setHTML(title)
199 self.show() 224 self.show()
200 225
201 # needed to update the contacts list when someone logged in/out 226 # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword)
202 self.host.room_contacts_chooser = self 227 self.presenceListener = self.refreshContactList
203 228 # update the contacts list when someone logged in/out
204 def getRoom(self, asSuffix=False): 229 self.host.addListener('presence', self.presenceListener, [C.PROF_KEY_NONE])
205 room = self.room_panel.getRoom() 230
206 if asSuffix: 231 @property
207 return room if room == "" else ": %s" % room 232 def room(self):
208 else: 233 """Get the room that has been selected or entered by the user
209 return room 234
210 235 @return: jid.JID or None
211 def getContacts(self, asSuffix=False): 236 """
212 contacts = self.contact_panel.getContacts() 237 return self.room_panel.room
213 if asSuffix: 238
214 return "" if contacts == [] else ": %s" % ", ".join(contacts) 239 @property
215 else: 240 def contacts(self):
216 return contacts 241 """Return the selected contacts.
242
243 @return: list[jid.JID]
244 """
245 return self.contact_panel.contacts
217 246
218 def onStackChanged(self, sender, index, visible=None): 247 def onStackChanged(self, sender, index, visible=None):
219 if visible is None: 248 if visible is None:
220 visible = sender.getWidget(index).getVisible() 249 visible = sender.getWidget(index).getVisible()
221 if index == 0: 250 if index == 0:
222 sender.setStackText(0, self.title_room + ("" if visible else self.getRoom(True))) 251 suffix = "" if (visible or not self.room) else ": %s" % self.room
252 sender.setStackText(0, self.title_room + suffix)
223 elif index == 1: 253 elif index == 1:
224 sender.setStackText(1, self.title_invite + ("" if visible else self.getContacts(True))) 254 suffix = "" if (visible or not self.contacts) else ": %s" % ", ".join([unicode(contact) for contact in self.contacts])
225 255 sender.setStackText(1, self.title_invite + suffix)
226 def resetContacts(self): 256
227 """Called when someone log in/out to update the list""" 257 def refreshContactList(self, *args, **kwargs):
228 self.contact_panel.setContacts(self.getContacts()) 258 """Called when someone log in/out to update the list.
259
260 @param args: set by the event call but not used here
261 """
262 self.contact_panel.refreshOptions(keep_selected=True)
229 263
230 def onOK(self, sender): 264 def onOK(self, sender):
231 room_jid = self.getRoom() 265 room = self.room # pyjamas issue: you need to use an intermediate variable to access a property's method
232 if room_jid != "" and "@" not in room_jid: 266 if room and not room.is_valid():
233 Window.alert('You must enter a room jid in the form room@chat.%s' % self.host._defaultDomain) 267 Window.alert('You must enter a room jid in the form room@chat.%s' % self.host._defaultDomain)
234 return 268 return
235 self.hide() 269 self.hide()
236 self.callback(room_jid, self.getContacts()) 270 self.callback(room, self.contacts)
237 271
238 def onCancel(self, sender): 272 def onCancel(self, sender):
239 self.hide() 273 self.hide()
240 274
241 def hide(self): 275 def hide(self):
242 self.host.room_contacts_chooser = None 276 self.host.removeListener('presence', self.presenceListener)
243 DialogBox.hide(self, autoClosed=True) 277 DialogBox.hide(self, autoClosed=True)
244 278
245 279
246 class GenericConfirmDialog(DialogBox): 280 class GenericConfirmDialog(DialogBox):
247 281
248 def __init__(self, widgets, callback, title='Confirmation', prompt=None, **kwargs): 282 def __init__(self, widgets, callback, title='Confirmation', prompt_widgets=None, **kwargs):
249 """ 283 """
250 Dialog to confirm an action 284 Dialog to confirm an action
251 @param widgets (list[Widget]): widgets to attach 285 @param widgets (list[Widget]): widgets to attach
252 @param callback: method to call when a button is clicked 286 @param callback (callable): method to call when a button is pressed,
287 with the following arguments:
288 - result (bool): set to True if the dialog has been confirmed
289 - *args: a list of unicode (the values for the prompt_widgets)
253 @param title: title of the dialog 290 @param title: title of the dialog
254 @param prompt (TextBox, list[TextBox]): input widgets from which to retrieve 291 @param prompt_widgets (list[TextBox]): input widgets from which to retrieve
255 the string value(s) to be passed to the callback when OK button is pressed. 292 the string value(s) to be passed to the callback when OK button is pressed.
256 If None, OK button will return "True". Cancel button always returns "False". 293 If None, OK button will return "True". Cancel button always returns "False".
257 """ 294 """
258 self.callback = callback 295 self.callback = callback
259 added_style = kwargs.pop('AddStyleName', None) 296 added_style = kwargs.pop('AddStyleName', None)
260 DialogBox.__init__(self, centered=True, **kwargs) 297 DialogBox.__init__(self, centered=True, **kwargs)
261 if added_style: 298 if added_style:
262 self.addStyleName(added_style) 299 self.addStyleName(added_style)
263 300
264 if prompt is None: 301 if prompt_widgets is None:
265 prompt = [] 302 prompt_widgets = []
266 elif isinstance(prompt, TextBox):
267 prompt = [prompt]
268 303
269 content = VerticalPanel() 304 content = VerticalPanel()
270 content.setWidth('100%') 305 content.setWidth('100%')
271 for wid in widgets: 306 for wid in widgets:
272 content.add(wid) 307 content.add(wid)
273 if wid in prompt: 308 if wid in prompt_widgets:
274 wid.setWidth('100%') 309 wid.setWidth('100%')
275 button_panel = HorizontalPanel() 310 button_panel = HorizontalPanel()
276 button_panel.addStyleName("marginAuto") 311 button_panel.addStyleName("marginAuto")
277 self.confirm_button = Button("OK", self.onConfirm) 312 self.confirm_button = Button("OK", self.onConfirm)
278 button_panel.add(self.confirm_button) 313 button_panel.add(self.confirm_button)
279 self.cancel_button = Button("Cancel", self.onCancel) 314 self.cancel_button = Button("Cancel", self.onCancel)
280 button_panel.add(self.cancel_button) 315 button_panel.add(self.cancel_button)
281 content.add(button_panel) 316 content.add(button_panel)
282 self.setHTML(title) 317 self.setHTML(title)
283 self.setWidget(content) 318 self.setWidget(content)
284 self.prompt = prompt 319 self.prompt_widgets = prompt_widgets
285 320
286 def onConfirm(self, sender): 321 def onConfirm(self, sender):
287 self.hide() 322 self.hide()
288 result = [box.getText() for box in self.prompt] if self.prompt else [True] 323 result = [True]
324 result.extend([box.getText() for box in self.prompt_widgets])
289 self.callback(*result) 325 self.callback(*result)
290 326
291 def onCancel(self, sender): 327 def onCancel(self, sender):
292 self.hide() 328 self.hide()
293 self.callback(False) 329 self.callback(False)
294 330
295 def show(self): 331 def show(self):
296 DialogBox.show(self) 332 DialogBox.show(self)
297 if self.prompt: 333 if self.prompt_widgets:
298 self.prompt[0].setFocus(True) 334 self.prompt_widgets[0].setFocus(True)
299 335
300 336
301 class ConfirmDialog(GenericConfirmDialog): 337 class ConfirmDialog(GenericConfirmDialog):
302 338
303 def __init__(self, callback, text='Are you sure ?', title='Confirmation', **kwargs): 339 def __init__(self, callback, text='Are you sure ?', title='Confirmation', **kwargs):
326 _body.setSize('100%', '100%') 362 _body.setSize('100%', '100%')
327 _body.setSpacing(4) 363 _body.setSpacing(4)
328 _body.add(main_widget) 364 _body.add(main_widget)
329 _body.setCellWidth(main_widget, '100%') 365 _body.setCellWidth(main_widget, '100%')
330 _body.setCellHeight(main_widget, '100%') 366 _body.setCellHeight(main_widget, '100%')
331 if not 'NO_CLOSE' in options: 367 if 'NO_CLOSE' not in options:
332 _close_button = Button("Close", self.onClose) 368 _close_button = Button("Close", self.onClose)
333 _body.add(_close_button) 369 _body.add(_close_button)
334 _body.setCellHorizontalAlignment(_close_button, HasAlignment.ALIGN_CENTER) 370 _body.setCellHorizontalAlignment(_close_button, HasAlignment.ALIGN_CENTER)
335 self.setHTML(title) 371 self.setHTML(title)
336 self.setWidget(_body) 372 self.setWidget(_body)
355 class PromptDialog(GenericConfirmDialog): 391 class PromptDialog(GenericConfirmDialog):
356 392
357 def __init__(self, callback, textes=None, values=None, title='User input', **kwargs): 393 def __init__(self, callback, textes=None, values=None, title='User input', **kwargs):
358 """Prompt the user for one or more input(s). 394 """Prompt the user for one or more input(s).
359 395
360 @param callback (callable): method to call when clicking OK 396 @param callback (callable): method to call when a button is pressed,
361 @param textes (str, list[str]): HTML textes to display before the inputs 397 with the following arguments:
362 @param values (str, list[str]): default values for each input 398 - result (bool): set to True if the dialog has been confirmed
363 @param title (str): dialog title 399 - *args: a list of unicode (the values entered by the user)
400 @param textes (list[unicode]): HTML textes to display before the inputs
401 @param values (list[unicode]): default values for each input
402 @param title (unicode): dialog title
364 """ 403 """
365 if textes is None: 404 if textes is None:
366 textes = [''] # display a single input without any description 405 textes = [''] # display a single input without any description
367 elif not isinstance(textes, list):
368 textes = [textes] # allow to pass a single string instead of a list
369 if values is None: 406 if values is None:
370 values = [] 407 values = []
371 elif not isinstance(values, list):
372 values = [values] # allow to pass a single string instead of a list
373 all_widgets = [] 408 all_widgets = []
374 prompt_widgets = [] 409 prompt_widgets = []
375 for count in xrange(len(textes)): 410 for count in xrange(len(textes)):
376 all_widgets.append(HTML(textes[count])) 411 all_widgets.append(HTML(textes[count]))
377 prompt = TextBox() 412 prompt = TextBox()
386 class PopupPanelWrapper(PopupPanel): 421 class PopupPanelWrapper(PopupPanel):
387 """This wrapper catch Escape event to avoid request cancellation by Firefox""" 422 """This wrapper catch Escape event to avoid request cancellation by Firefox"""
388 423
389 def onEventPreview(self, event): 424 def onEventPreview(self, event):
390 if event.type in ["keydown", "keypress", "keyup"] and event.keyCode == KEY_ESCAPE: 425 if event.type in ["keydown", "keypress", "keyup"] and event.keyCode == KEY_ESCAPE:
391 #needed to prevent request cancellation in Firefox 426 # needed to prevent request cancellation in Firefox
392 event.preventDefault() 427 event.preventDefault()
393 return PopupPanel.onEventPreview(self, event) 428 return PopupPanel.onEventPreview(self, event)
394 429
395 430
396 class ExtTextBox(TextBox): 431 class ExtTextBox(TextBox):
526 self.add(_label) 561 self.add(_label)
527 self.setCellWidth(_label, "100%") 562 self.setCellWidth(_label, "100%")
528 minus_button = Button("-", self.onMinus) 563 minus_button = Button("-", self.onMinus)
529 self.box = WheelTextBox() 564 self.box = WheelTextBox()
530 self.box.setVisibleLength(visible_len) 565 self.box.setVisibleLength(visible_len)
531 self.box.setText(str(value)) 566 self.box.setText(unicode(value))
532 self.box.addInputListener(self) 567 self.box.addInputListener(self)
533 self.box.addMouseWheelListener(self) 568 self.box.addMouseWheelListener(self)
534 plus_button = Button("+", self.onPlus) 569 plus_button = Button("+", self.onPlus)
535 self.add(minus_button) 570 self.add(minus_button)
536 self.add(self.box) 571 self.add(self.box)
549 listener(self.value) 584 listener(self.value)
550 585
551 def setValue(self, value): 586 def setValue(self, value):
552 """Change the value and fire valueChange listeners""" 587 """Change the value and fire valueChange listeners"""
553 self.value = value 588 self.value = value
554 self.box.setText(str(value)) 589 self.box.setText(unicode(value))
555 self._callListeners() 590 self._callListeners()
556 591
557 def onMinus(self, sender, step=1): 592 def onMinus(self, sender, step=1):
558 self.value = max(0, self.value - step) 593 self.value = max(0, self.value - step)
559 self.box.setText(str(self.value)) 594 self.box.setText(unicode(self.value))
560 self._callListeners() 595 self._callListeners()
561 596
562 def onPlus(self, sender, step=1): 597 def onPlus(self, sender, step=1):
563 self.value += step 598 self.value += step
564 if self.value_max: 599 if self.value_max:
565 self.value = min(self.value, self.value_max) 600 self.value = min(self.value, self.value_max)
566 self.box.setText(str(self.value)) 601 self.box.setText(unicode(self.value))
567 self._callListeners() 602 self._callListeners()
568 603
569 def onInput(self, sender): 604 def onInput(self, sender):
570 """Accept only valid integer && normalize print (no leading 0)""" 605 """Accept only valid integer && normalize print (no leading 0)"""
571 try: 606 try:
572 self.value = int(self.box.getText()) if self.box.getText() else 0 607 self.value = int(self.box.getText()) if self.box.getText() else 0
573 except ValueError: 608 except ValueError:
574 pass 609 pass
575 if self.value_max: 610 if self.value_max:
576 self.value = min(self.value, self.value_max) 611 self.value = min(self.value, self.value_max)
577 self.box.setText(str(self.value)) 612 self.box.setText(unicode(self.value))
578 self._callListeners() 613 self._callListeners()
579 614
580 def onMouseWheel(self, sender, velocity): 615 def onMouseWheel(self, sender, velocity):
581 if velocity > 0: 616 if velocity > 0:
582 self.onMinus(sender, 10) 617 self.onMinus(sender, 10)