Package orm2 :: Package ui :: Package xist :: Module widgets
[hide private]
[frames] | no frames]

Source Code for Module orm2.ui.xist.widgets

  1  #!/usr/bin/env python 
  2  # -*- coding: iso-8859-1 -*- 
  3   
  4  ##  This file is part of orm, The Object Relational Membrane Version 2. 
  5  ## 
  6  ##  Copyright 2002-2006 by Diedrich Vorberg <diedrich@tux4web.de> 
  7  ## 
  8  ##  All Rights Reserved 
  9  ## 
 10  ##  For more Information on orm see the README file. 
 11  ## 
 12  ##  This program is free software; you can redistribute it and/or modify 
 13  ##  it under the terms of the GNU General Public License as published by 
 14  ##  the Free Software Foundation; either version 2 of the License, or 
 15  ##  (at your option) any later version. 
 16  ## 
 17  ##  This program is distributed in the hope that it will be useful, 
 18  ##  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 19  ##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 20  ##  GNU General Public License for more details. 
 21  ## 
 22  ##  You should have received a copy of the GNU General Public License 
 23  ##  along with this program; if not, write to the Free Software 
 24  ##  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 25  ## 
 26  ##  I have added a copy of the GPL in the file gpl.txt. 
 27   
 28  # 
 29  # $Log: widgets.py,v $ 
 30  # Revision 1.15  2007/07/04 09:47:43  diedrich 
 31  # Changed password widget's param names 
 32  # 
 33  # Revision 1.14  2007/06/14 22:47:42  diedrich 
 34  # Added size, multiple and multiple_separator to mapping_select widget. 
 35  # 
 36  # Revision 1.13  2007/06/07 16:54:04  diedrich 
 37  # Added just_dislpay widget. 
 38  # 
 39  # Revision 1.12  2007/05/09 17:20:56  diedrich 
 40  # Added password widget. 
 41  # 
 42  # Revision 1.11  2007/04/17 17:14:28  diedrich 
 43  # Added mapping_select. 
 44  # 
 45  # Revision 1.10  2007/04/14 20:37:57  diedrich 
 46  # Conditionally import ll.xist.errors. 
 47  # 
 48  # Revision 1.9  2007/01/22 19:45:46  diedrich 
 49  # Added a parameter to mapping_radiobuttons that determines whether they 
 50  # each are in a <div> or not. 
 51  # 
 52  # Revision 1.8  2006/10/07 22:10:18  diedrich 
 53  # Fixed error message handling. 
 54  # 
 55  # Revision 1.7  2006/09/04 15:58:42  diedrich 
 56  # Bug fixing 
 57  # 
 58  # Revision 1.6  2006/07/08 17:12:56  diedrich 
 59  # - added hidden_primary_key class 
 60  # - changed checkbox.row() 
 61  # - added datetime_input class 
 62  # 
 63  # Revision 1.5  2006/07/05 21:44:13  diedrich 
 64  # - Added utext, mapping_radiobutton 
 65  # - Several changed 
 66  # 
 67  # Revision 1.4  2006/07/04 22:51:23  diedrich 
 68  # - Implemented belongs_to() methods 
 69  # - Added get_from_result() and set_from_result() 
 70  # 
 71  # Revision 1.3  2006/06/11 23:48:14  diedrich 
 72  # Fixed value() 
 73  # 
 74  # Revision 1.2  2006/06/10 18:08:17  diedrich 
 75  # Rewrote the whole thing to make sense. Introduced widget/actual_widget 
 76  # seperation 
 77  # 
 78  # Revision 1.1  2006/05/15 21:43:31  diedrich 
 79  # Initial commit 
 80  # 
 81  # Revision 1.1  2006/04/28 09:56:41  diedrich 
 82  # Initial commit 
 83  # 
 84  # 
 85   
 86  import sys, datetime, time 
 87  from string import * 
 88  from types import * 
 89   
 90  from orm2.ui import widget 
 91  from orm2.validators import * 
 92  from orm2 import datatypes 
 93  from orm2.exceptions import * 
 94   
 95  from i18n import translate, _ 
 96   
 97  from ll.xist.ns import html, xml, chars 
 98  from ll.xist.xsc import * 
 99  from ll.xist import parsers 
100   
101  try: 
102      from ll.xist.errors import NodeNotFoundError 
103  except ImportError: 
104      # The exception classes from the errors module have been moved to 
105      # xsc. 
106      pass 
107   
108   
109 -class xist_widget(widget):
110
111 - def belongs_to(self, module_name):
112 return module_name == "xist"
113
114 - class actual_widget(widget.actual_widget):
115 - def __init__(self, dbobj, dbproperty, errors={}, 116 name=None, title=None, help="", default=None, **kw):
117 """ 118 @param dbobj: The dbobj whoes property is to be displayed by this 119 widget 120 @param errors: Dict that contains the error messages from the last 121 commit. 122 @param name: The name attribute of the HTML <input> (or so) element 123 that will be created by this. Defaults to dbclass.attribute, 124 which will do for most circumstances... A regular String. 125 @param title: Will overwrite the datatype.title attribute for the 126 widget's caption. Unicode string required. 127 @param help: Help text that will be displayed along with the 128 widget. May be a XIST element, of course, but you may not want 129 to use block level elements in it. 130 @param default: Unicode String or other Python object suitable to 131 determine the default setting for this widget if dbobj is None 132 (see widget() below) 133 134 The key word arguments may be used to pass arbitrary 135 attributes to the widget element. 136 """ 137 widget.actual_widget.__init__(self, dbobj, dbproperty) 138 self.errors = errors 139 140 if name is None: 141 self.name = "%s_%s" % ( dbproperty.dbclass.__name__, 142 dbproperty.attribute_name, ) 143 else: 144 if type(name) != StringType: 145 msg = "HTML name property must be string not %s"%repr(name) 146 raise TypeError(msg) 147 148 self.name = name 149 150 if title is None: 151 self.title = translate(self.dbproperty.title, self) 152 else: 153 self.title = title 154 155 if help is None: 156 self._help = Frag() 157 else: 158 self._help = translate(help, self) 159 160 self.default = default 161 162 self.extra_args = kw
163
164 - def widget(self, **kw):
165 """ 166 Returns a xist frag that represents the HTML to create the 167 widget. Ideally this is a single HTML element. The key 168 word arguments will be passed as attributes, overwriting 169 the constructor's key word arguments (see above). 170 """ 171 raise NotImplementedError()
172
173 - def help(self, **kw):
174 """ 175 @returns: A html.div instance containing the help 176 message. The key word arguments will be added to the <div> 177 as arguments. The css class defaults to 'help' 178 """ 179 if not kw.has_key("class_"): 180 kw["class_"] = "help" 181 182 if self._help: 183 return html.div(self._help, **kw) 184 else: 185 return Frag()
186
187 - def label(self, **kw):
188 """ 189 @returns: A html.div instance containing the widget's label 190 (title attribute). The key word arguments will be added to the 191 <div> as arguments. The css class defaults to 'label' 192 """ 193 if not kw.has_key("class_"): 194 kw["class_"] = "label" 195 196 required = False 197 for validator in self.dbproperty.validators: 198 if isinstance(validator, not_null_validator) or \ 199 isinstance(validator, not_empty_validator): 200 required = True 201 break 202 203 if required: 204 kw["class_"] += " required" 205 206 return html.div(self.title, **kw)
207
208 - def error_message(self, error):
209 ''' 210 Return a <div class="error"> with the formated error 211 message in it. 212 ''' 213 if error is not None: 214 if type(error) in (ListType, TupleType,): 215 if len(error) > 1: 216 ul = html.ul() 217 for e in error: 218 ul.append(html.li(translate(e, self))) 219 220 error = ul 221 else: 222 error = translate(error[0], self) 223 else: 224 error = translate(error, self) 225 226 error = html.div(error, class_="error") 227 228 return error 229 else: 230 return Frag()
231
232 - def row(self, plone=False, error=None, **kw):
233 ''' 234 Return a row for an HTML form 235 236 <div class="row"> 237 <div class="label">self.title</div> 238 <div class="help">self._help if non-null</div> 239 <div class="error">error if non-null</div> 240 241 <div class="field"> 242 self.widget() 243 </div> 244 </div> 245 246 @param plone: Set attributes so that this form may be used with 247 CMFPlone`s JavaScript (unimplemented) 248 @param error: Error message to be displayed along with the widget. 249 ''' 250 return html.div(self.label(), self.help(), 251 self.error_message(error), 252 html.div(self.widget(**kw), class_="field"), 253 class_="row")
254
255 - def value(self):
256 """ 257 If the current request contains a value for our form element's 258 name, return that value, otherwise get it from the dbobj. If 259 that should fail, return the default. 260 """ 261 try: 262 ret = self.get_from_request(use_default=False) 263 except KeyError: 264 if self.dbproperty.isset(self.dbobj): 265 ret = self.dbproperty.__get__(self.dbobj) 266 else: 267 ret = self.default 268 269 return ret
270
271 - def get_from_request(self, use_default=False):
272 """ 273 Check the request for a parameter with this widget's name 274 attribute. It it is set return it as is. Otherwise return 275 the default value (if use_default is True) or raise 276 KeyError. 277 """ 278 REQUEST = self.REQUEST 279 280 if REQUEST.has_key(self.name): 281 return REQUEST[self.name] 282 else: 283 if use_default: 284 return self.default 285 else: 286 raise KeyError("REQUEST does not contain %s param" % \ 287 self.name)
288
289 - def set_from_request(self, use_default=False, ignore_if_unset=False):
290 """ 291 The the dbattribute this widget is responsible for from REQUEST 292 (using L{get_from_request} above). 293 294 @param REQUEST: Zope request object (or any other dict for that 295 matter) 296 @param use_default: Use this widget's default value if the REQUEST 297 does not contain an appropriate value. 298 @raises: KeyError if the REQUEST does not contain an appropriate 299 value. 300 """ 301 try: 302 self.dbproperty.__set__(self.dbobj, 303 self.get_from_request(False)) 304 except KeyError: 305 if ignore_if_unset: 306 pass 307 else: 308 raise
309 310
311 - def __getattr__(self, name):
312 """ 313 Since this class is used almost exclusively inside Zope, 314 this will hook it into Zope's acquisition mechanism. 315 """ 316 if not hasattr(self, "context"): 317 self.context = self.dbobj.__ds__().context 318 if name == "context": return self.context 319 320 return getattr(self.context, name)
321 322 323
324 -class _input(xist_widget):
325 ''' 326 Base class for <input /> element based widgets. The type= attribute is 327 determined by the class name. 328 '''
329 - class actual_widget(xist_widget.actual_widget):
330 - def widget(self, **kw):
331 extra_args = self.extra_args.copy() 332 extra_args.update(kw) 333 334 return html.input(type=self.type, 335 value=self.value(), 336 name=self.name, **extra_args)
337 338
339 -class just_display(xist_widget):
340 """ 341 Simply display a piece of information with no <input> whatsoever. 342 """
343 - class actual_widget(xist_widget.actual_widget):
344 - def widget(self, **kw):
345 return html.span(self.value(), class_="just-display")
346 347 348
349 -class text(_input):
350 """ 351 352 """
353 - def __init__(self, empty_to_none=False, **kw):
354 """ 355 @param mapping: A list of pairs as ( 'identifyer', u'title', ) that 356 will be used to create the widget. 357 @param sort: Boolean value that determins if the mapping will be 358 sorted by its title component before any HTML is created from it. 359 """ 360 xist_widget.__init__(self, **kw) 361 self.empty_to_none = empty_to_none
362
363 - def __call__(self, dbobj, **kw):
364 params = self.params.copy() 365 params.update(kw) 366 367 return self.actual_widget(dbobj, self.dbproperty, 368 self.empty_to_none, **params)
369
370 - class actual_widget(_input.actual_widget):
371 type = "text" 372
373 - def __init__(self, dbobj, dbproperty, empty_to_none, **kw):
374 _input.actual_widget.__init__(self, dbobj, dbproperty, **kw) 375 self.empty_to_none = empty_to_none
376
377 - def value(self):
378 u = xist_widget.actual_widget.value(self) 379 380 if u is None: 381 return u"" 382 elif type(u) != UnicodeType: 383 u = unicode(u) 384 385 return u
386
387 - def get_from_request(self, use_default=False):
388 """ 389 Check the request for a parameter with this widget's name 390 attribute. It it is set return it as is. Otherwise return 391 the default value (if use_default is True) or raise 392 KeyError. 393 """ 394 if self.REQUEST.has_key(self.name): 395 ret = self.REQUEST[self.name] 396 397 if ret == "" and self.empty_to_none: 398 return None 399 else: 400 return ret 401 else: 402 if use_default: 403 return self.default 404 else: 405 raise KeyError("REQUEST does not contain %s param" % \ 406 self.name)
407
408 -class utext(text):
409 """ 410 This widget will enforce that the object handled is a unicode string 411 (rather than attempting to cast it into one like text does). 412 """ 413
414 - class actual_widget(text.actual_widget):
415 type = "text" 416
417 - def value(self):
418 u = text.actual_widget.value(self) 419 420 if u is None: 421 return u"" 422 elif type(u) != UnicodeType: 423 msg = "dbattributes managed by a %s.%s widget must " + \ 424 "return a Unicode object! (%s.%s returned %s)" 425 msg = msg % ( self.__class__.__module__, 426 self.__class__.__name__, 427 self.dbobj.__class__.__name__, 428 self.dbproperty.attribute_name, 429 repr(u), ) 430 raise TypeError(msg) 431 432 return u
433
434 - def get_from_request(self, use_default=False):
435 u = text.actual_widget.get_from_request(self, use_default) 436 437 request_charset = "utf-8" 438 439 if u is not None: 440 u = unicode(u, request_charset) 441 442 return u
443
444 -class password(utext):
445 """ 446 The password widgets consits of two <input type=password> elements 447 that are wrapped in <div class=password-input-container>s so you 448 can position them. So the resulting HTML looks like 449 450 <div> 451 <div class=password-input-container> 452 <input name=password_name0> 453 </div> 454 <div class=password-input-container> 455 <input name=password_name1> 456 </div> 457 </div> 458 459 The two entries must match, naturally, and will always be ignored 460 if both are empty. 461 """
462 - class actual_widget(utext.actual_widget):
463 type = "password" 464
465 - def extra_pw_name(self):
466 return "password_check_" + self.name
467
468 - def widget(self, **kw):
469 extra_args = self.extra_args.copy() 470 extra_args.update(kw) 471 472 return html.div(html.div(html.input(type=self.type, 473 value=self.value(), 474 name=self.name, 475 **extra_args), 476 class_="password-input-container"), 477 html.div(html.input(type=self.type, 478 value=self.value(), 479 name=self.extra_pw_name(), 480 **extra_args), 481 class_="password-input-container"))
482
483 - def get_from_request(self, use_default=False):
484 """ 485 Gets the value of both password fields from the request. 486 Returns None if they are not set or if the passwords don't 487 match. This must be cought in the dbobj's validator! 488 """ 489 REQUEST = self.REQUEST 490 491 if REQUEST.has_key(self.name) or \ 492 REQUEST.has_key(self.extra_pw_name()): 493 one = REQUEST.get(self.name, "") 494 two = REQUEST.get(self.extra_pw_name(), "") 495 496 if one == "" and two == "": 497 return None 498 else: 499 if one == two: 500 return unicode(one) 501 else: 502 # return None 503 raise PasswordsDontMatch() 504 505 return None
506
507 - def set_from_request(self, use_default=False, ignore_if_unset=True):
508 """ 509 A default value will never be used. 510 A password will always be ignored it not set. This also means, 511 empty passwords are impossible. 512 """ 513 v = self.get_from_request() 514 if v is not None: 515 self.dbproperty.__set__(self.dbobj, v)
516 517 518
519 -class hidden(text):
520 - class actual_widget(text.actual_widget):
521 type = "hidden" 522
523 - def label(self): return Frag()
524
525 - def row(self, plone=False, error=None, **kw):
526 return self.widget(**kw)
527
528 -class hidden_primary_key(hidden):
529 """ 530 Special hidden widget for primary keys. The set_from_request() method 531 does nothing, because this doesn't make sense for primary keys. 532 """
533 - class actual_widget(hidden.actual_widget):
534 - def set_from_request(self, use_default=False, ignore_if_unset=False):
535 """ 536 The primary key is never set. 537 """ 538 pass
539 540
541 -class checkbox(_input):
542 - class actual_widget(xist_widget.actual_widget):
543 type = "checkbox" 544
545 - def widget(self, **kw):
546 extra_args = self.extra_args.copy() 547 extra_args.update(kw) 548 549 value = self.value() 550 551 if value: 552 checked = "checked" 553 else: 554 checked = None 555 556 cbid = "check-box-%i" % id(self) 557 return html.div(html.input(type="checkbox", checked=checked, 558 name=self.name, id=cbid), 559 html.label(self.title, for_=cbid), 560 class_="checkbox", **extra_args)
561
562 - def label(self, **lw):
563 return Frag()
564
565 - def row(self, plone=False, error=None, **kw):
566 ret = self.widget(**kw) 567 ret.insert(0, self.error_message(error)) 568 ret.append(self.help(**kw)) 569 return ret
570 571
572 - def value(self):
573 """ 574 This assumes that forms set either submitted or form_submitted 575 on submitb 576 """ 577 if self.REQUEST.has_key("submitted") or \ 578 self.REQUEST.has_key("form_submitted"): 579 ret = self.get_from_request() 580 else: 581 if self.dbproperty.isset(self.dbobj): 582 ret = self.dbproperty.__get__(self.dbobj) 583 else: 584 ret = self.default 585 586 return bool(ret)
587
588 - def get_from_request(self, use_default=False):
589 """ 590 Check the request for a parameter with this widget's name 591 attribute. It it is set return it as is. Otherwise return 592 the default value (if use_default is True) or raise 593 KeyError. 594 """ 595 return self.REQUEST.has_key(self.name)
596
597 -class textarea(text):
598 - class actual_widget(text.actual_widget):
599 - def widget(self, **kw):
600 extra_args = self.extra_args.copy() 601 extra_args.update(kw) 602 603 return html.textarea(self.value(), name=self.name, **extra_args)
604
605 -class utextarea(utext):
606 """ 607 This is analogous for textarea what utext is to text. 608 """ 609 actual_widget = textarea.actual_widget
610 611
612 -class mapping_radiobuttons(xist_widget):
613 - def __init__(self, mapping, sort=False, div=True, **kw):
614 """ 615 @param mapping: A list of pairs as ( 'identifyer', u'title', ) that 616 will be used to create the widget. 617 @param sort: Boolean value that determins if the mapping will be 618 sorted by its title component before any HTML is created from it. 619 @param div: Add a <div> around a <input>/<label> pair to position the 620 radio buttons vertically. Defaults to True. 621 """ 622 xist_widget.__init__(self, **kw) 623 self.mapping = mapping 624 self.sort = sort 625 self.div = div
626
627 - def __call__(self, dbobj, **kw):
628 params = self.params.copy() 629 params.update(kw) 630 631 return self.actual_widget(dbobj, self.dbproperty, 632 self.mapping, self.sort, self.div, **params)
633
634 - class actual_widget(xist_widget.actual_widget):
635 - def __init__(self, dbobj, dbproperty, mapping, sort, div, **kw):
636 xist_widget.actual_widget.__init__(self, dbobj, dbproperty, **kw) 637 self._mapping = mapping 638 self.sort = sort 639 self.div = div
640
641 - def widget(self, **kw):
642 extra_args = self.extra_args.copy() 643 extra_args.update(kw) 644 645 ret = html.div(**extra_args) 646 current = self.value() 647 648 for name, title in self.mapping(): 649 radio_button_id = "radio-button-%i" % id(name) 650 651 if name == current: 652 checked = 'checked' 653 else: 654 checked = None 655 656 button = Frag(html.input(type="radio", name=self.name, 657 value=name, checked=checked, 658 id=radio_button_id), 659 html.label(title, for_=radio_button_id)) 660 661 if self.div: 662 ret.append(html.div(button, class_="radio-button-row")) 663 else: 664 ret.append(button, " ") 665 666 return ret
667
668 - def mapping(self):
669 mapping = self._mapping 670 671 if self.sort: 672 mapping = mapping.sorted(lambda a, b: cmp(a[1], b[1])) 673 674 return mapping
675
676 -class mapping_select(xist_widget):
677 - def __init__(self, mapping, sort=False, size=1, 678 multiple=False, multiple_separator=None, 679 **kw):
680 """ 681 @param mapping: A list of pairs as ( 'identifyer', u'title', ) that 682 will be used to create the widget. 683 @param sort: Boolean value that determins if the mapping will be 684 sorted by its title component before any HTML is created from it, 685 defaults to False. 686 @param size: Size parameter to the <select> tag. Defaults to 1. 687 @param multiple: Determine whether the user will be able to select 688 multiple items from the mapping. Defaults to False. 689 @param multiple_separator: This parameter only has an effect if 690 multiple is True. If set to a non-Null value, data received 691 from the web client will be flattened to a single string, 692 concatinated by MULTIPLE_SEPARATOR. If set to None (the default), 693 the data will always be represented as a list of strings. 694 """ 695 xist_widget.__init__(self, **kw) 696 self.mapping = mapping 697 self.sort = sort 698 self.size = size 699 self.multiple = multiple 700 self.multiple_separator = multiple_separator
701
702 - def __call__(self, dbobj, **kw):
703 params = self.params.copy() 704 params.update(kw) 705 706 return self.actual_widget(dbobj, self.dbproperty, 707 self.mapping, self.sort, self.size, 708 self.multiple, self.multiple_separator, 709 **params)
710
711 - class actual_widget(xist_widget.actual_widget):
712 - def __init__(self, dbobj, dbproperty, mapping, sort, 713 size, multiple, multiple_separator, **kw):
714 xist_widget.actual_widget.__init__(self, dbobj, dbproperty, **kw) 715 self._mapping = mapping 716 self.sort = sort 717 self.size = size 718 self.multiple = multiple 719 self.multiple_separator = multiple_separator
720
721 - def widget(self, **kw):
722 extra_args = self.extra_args.copy() 723 extra_args.update(kw) 724 725 multiple = {True: "multiple", False: None}[self.multiple] 726 727 ret = html.select(name=self.name, 728 size=self.size, 729 multiple=multiple, **extra_args) 730 current = self.value() 731 732 if self.multiple: 733 if self.multiple_separator is not None: 734 current = split(current, self.multiple_separator) 735 else: 736 if type(current) != ListType: 737 raise TypeError("A mapping_select with multiple set " 738 "only works on dbproperties that " 739 "accept and return list values") 740 741 for name, title in self.mapping(): 742 if name in current: 743 selected = 'selected' 744 else: 745 selected = None 746 747 ret.append(html.option(title, value=name, 748 selected=selected)) 749 else: 750 for name, title in self.mapping(): 751 if name == current: 752 selected = 'selected' 753 else: 754 selected = None 755 756 ret.append(html.option(title, value=name, 757 selected=selected)) 758 759 return ret
760
761 - def mapping(self):
762 mapping = self._mapping 763 764 if self.sort: 765 mapping = mapping.sorted(lambda a, b: cmp(a[1], b[1])) 766 767 return mapping
768
769 - def get_from_request(self, use_default=False):
770 value = xist_widget.actual_widget.get_from_request(self, 771 use_default) 772 if self.multiple: 773 # Turn the value into a list 774 if type(value) != ListType: value = [ value, ] 775 776 if self.multiple_separator is not None: 777 value = join(value, self.multiple_separator) 778 779 return value
780
781 -class datetime_input(text):
782 - def __init__(self, format, target_cls=None, empty_to_none=False, **kw):
783 """ 784 @param format: strftime()/strptime() compatible format string (see 785 U{http://docs.python.org/lib/module-time.html} 786 @param farget_class: Either datetime.date or datetime.datetime. Any 787 compatible class (providing a fromtimestamp() 788 constructor with the same semantics) will also work. If set to None 789 (the default) the class of the dbproperty will determin the class 790 used. 791 """ 792 text.__init__(self, empty_to_none, **kw) 793 self.format = format 794 self.target_cls = target_cls
795
796 - def __call__(self, dbobj, **kw):
797 params = self.params.copy() 798 params.update(kw) 799 800 return self.actual_widget(dbobj, self.dbproperty, 801 self.empty_to_none, 802 self.format, self.target_cls, 803 **params)
804
805 - class actual_widget(text.actual_widget):
806 - def __init__(self, dbobj, dbproperty, empty_to_none, 807 format, target_cls, **kw):
808 text.actual_widget.__init__(self, dbobj, dbproperty, 809 empty_to_none, **kw) 810 self.format = format 811 812 if target_cls is None: 813 if isinstance(dbproperty, datatypes.datetime): 814 self.target_cls = datetime.datetime 815 elif isinstance(dbproperty, datatypes.date): 816 self.target_cls = datetime.date 817 else: 818 raise TypeError("You must specify a target_cls for "+\ 819 "datetime_input if it's not used with "+\ 820 "datatype.date or datetime.") 821 else: 822 self.target_cls = target_cls
823 824
825 - def value(self):
826 try: 827 v = xist_widget.actual_widget.value(self) 828 except DateValidatorException: 829 # A date value that can't be pased is re-displayed 830 # and fails in the get_from_request() method below. 831 # This should probably be done more obviously. 832 v = text.actual_widget.get_from_request(self) 833 834 if v is None or v == "": 835 return u"" 836 elif isinstance(v, (datetime.datetime, datetime.date,) ): 837 return v.strftime(self.format) 838 else: 839 if type(v) == UnicodeType: 840 return v 841 else: 842 return unicode(v)
843
844 - def get_from_request(self, use_default=False):
845 s = text.actual_widget.get_from_request(self, use_default) 846 847 if s is None or ( s == "" and self.empty_to_none ): 848 return None 849 else: 850 try: 851 time_t = time.strptime(s, self.format) 852 except ValueError: 853 raise DateValidatorException( 854 "Can't parse date %s using (%s) " % ( 855 repr(s), repr(self.format), ), 856 self.dbobj, self.dbproperty, s, self.format) 857 858 try: 859 timestamp = time.mktime(time_t) 860 return self.target_cls.fromtimestamp(timestamp) 861 except OverflowError: 862 y, m, d, H, M, S, d1, d2, d3 = time_t 863 if self.target_cls == datetime.datetime: 864 return datetime.datetime(year=y, day=d, month=m, 865 hour=H, minute=M, second=S) 866 elif self.target_cls == datetime.date: 867 return datetime.date(year=y, month=m, day=d) 868 else: 869 raise
870 871 872 873 # Local variables: 874 # mode: python 875 # ispell-local-dictionary: "english" 876 # End: 877