Mercurial > libervia-web
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) |