1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Defines the top-level interface that is and must be implemented by
17 all Muntjac components."""
18
19 from muntjac.terminal.variable_owner import IVariableOwner
20 from muntjac.terminal.sizeable import ISizeable
21 from muntjac.terminal.paintable import IPaintable
22 from muntjac.util import EventObject, IEventListener
23
24
25 -class IComponent(IPaintable, IVariableOwner, ISizeable):
26 """C{IComponent} is the top-level interface that is and must be
27 implemented by all Muntjac components. C{IComponent} is paired with
28 L{AbstractComponent}, which provides a default implementation for
29 all the methods defined in this interface.
30
31 Components are laid out in the user interface hierarchically. The layout
32 is managed by layout components, or more generally by components that
33 implement the L{ComponentContainer} interface. Such a container is
34 the I{parent} of the contained components.
35
36 The L{getParent} method allows retrieving the parent component
37 of a component. While there is a L{setParent}, you rarely need
38 it as you normally add components with the
39 L{addComponent()<ComponentContainer.addComponent>} method
40 of the layout or other C{ComponentContainer}, which automatically
41 sets the parent.
42
43 A component becomes I{attached} to an application (and the
44 L{attach} is called) when it or one of its parents is attached to
45 the main window of the application through its containment hierarchy.
46
47 @author: Vaadin Ltd.
48 @author: Richard Lincoln
49 @version: 1.1.2
50 """
51
53 """Gets all user-defined CSS style names of a component. If the
54 component has multiple style names defined, the return string is a
55 space-separated list of style names. Built-in style names defined in
56 Muntjac or GWT are not returned.
57
58 The style names are returned only in the basic form in which they
59 were added; each user-defined style name shows as two CSS style class
60 names in the rendered HTML: one as it was given and one prefixed with
61 the component-specific style name. Only the former is returned.
62
63 @return: the style name or a space-separated list of user-defined
64 style names of the component
65 @see: L{setStyleName}
66 @see: L{addStyleName}
67 @see: L{removeStyleName}
68 """
69 raise NotImplementedError
70
71
73 """Sets one or more user-defined style names of the component,
74 replacing any previous user-defined styles. Multiple styles can be
75 specified as a space-separated list of style names. The style names
76 must be valid CSS class names and should not conflict with any
77 built-in style names in Muntjac or GWT::
78
79 label = new Label("This text has a lot of style")
80 label.setStyleName("myonestyle myotherstyle")
81
82 Each style name will occur in two versions: one as specified and one
83 that is prefixed with the style name of the component. For example,
84 if you have a C{Button} component and give it "C{mystyle}"
85 style, the component will have both "C{mystyle}" and
86 "C{v-button-mystyle}" styles. You could then style the component
87 either with::
88
89 .myonestyle {background: blue;}
90
91 or::
92
93 .v-button-myonestyle {background: blue;}
94
95 It is normally a good practice to use L{addStyleName} rather than this
96 setter, as different software abstraction layers can then add their own
97 styles without accidentally removing those defined in other layers.
98
99 This method will trigger a L{RepaintRequestEvent}.
100
101 @param style:
102 the new style or styles of the component as a
103 space-separated list
104 @see: L{getStyleName}
105 @see: L{addStyleName}
106 @see: L{removeStyleName}
107 """
108 raise NotImplementedError
109
110
112 """Adds a style name to component. The style name will be rendered as
113 a HTML class name, which can be used in a CSS definition::
114
115 label = new Label("This text has style")
116 label.addStyleName("mystyle")
117
118 Each style name will occur in two versions: one as specified and one
119 that is prefixed wil the style name of the component. For example, if
120 you have a C{Button} component and give it "C{mystyle}"
121 style, the component will have both "C{mystyle}" and
122 "C{v-button-mystyle}" styles. You could then style the component
123 either with::
124
125 .mystyle {font-style: italic;}
126
127 or::
128
129 .v-button-mystyle {font-style: italic;}
130
131 This method will trigger a L{RepaintRequestEvent}.
132
133 @param style:
134 the new style to be added to the component
135 @see: L{getStyleName}
136 @see: L{setStyleName}
137 @see: L{removeStyleName}
138 """
139 raise NotImplementedError
140
141
143 """Removes one or more style names from component. Multiple styles
144 can be specified as a space-separated list of style names.
145
146 The parameter must be a valid CSS style name. Only user-defined style
147 names added with L{addStyleName} or L{setStyleName} can be removed;
148 built-in style names defined in Muntjac or GWT can not be removed.
149
150 This method will trigger a L{RepaintRequestEvent}.
151
152 @param style:
153 the style name or style names to be removed
154 @see: L{getStyleName}
155 @see: L{setStyleName}
156 @see: L{addStyleName}
157 """
158 raise NotImplementedError
159
160
162 """Tests whether the component is enabled or not. A user can not
163 interact with disabled components. Disabled components are rendered
164 in a style that indicates the status, usually in gray color. Children
165 of a disabled component are also disabled. Components are enabled by
166 default.
167
168 As a security feature, all variable change events for disabled
169 components are blocked on the server-side.
170
171 @return: C{True} if the component and its parent are enabled,
172 C{False} otherwise.
173 @see: L{IVariableOwner.isEnabled}
174 """
175 raise NotImplementedError
176
177
179 """Enables or disables the component. The user can not interact
180 disabled components, which are shown with a style that indicates the
181 status, usually shaded in light gray color. Components are enabled
182 by default. Children of a disabled component are automatically
183 disabled; if a child component is explicitly set as disabled, changes
184 in the disabled status of its parents do not change its status::
185
186 enabled = new Button("Enabled")
187 enabled.setEnabled(True) # the default
188 layout.addComponent(enabled)
189
190 disabled = Button("Disabled")
191 disabled.setEnabled(False)
192 layout.addComponent(disabled)
193
194 This method will trigger a L{RepaintRequestEvent} for the
195 component and, if it is a L{ComponentContainer}, for all its
196 children recursively.
197
198 @param enabled:
199 a boolean value specifying if the component should be
200 enabled or not
201 """
202 raise NotImplementedError
203
204
206 """Tests the I{visibility} property of the component.
207
208 Visible components are drawn in the user interface, while invisible
209 ones are not. The effect is not merely a cosmetic CSS change, but the
210 entire HTML element will be empty. Making a component invisible
211 through this property can alter the positioning of other components.
212
213 A component is visible only if all its parents are also visible.
214 Notice that if a child component is explicitly set as invisible,
215 changes in the visibility status of its parents do not change its
216 status.
217
218 This method does not check whether the component is attached (see
219 L{attach}). The component and all its parents may be
220 considered "visible", but not necessarily attached to application.
221 To test if component will actually be drawn, check both its visibility
222 and that L{getApplication} does not return C{None}.
223
224 @return: C{True} if the component is visible in the user
225 interface, C{False} if not
226 @see: L{setVisible}
227 @see: L{attach}
228 """
229 raise NotImplementedError
230
231
233 """Sets the visibility of the component.
234
235 Visible components are drawn in the user interface, while invisible
236 ones are not. The effect is not merely a cosmetic CSS change, but the
237 entire HTML element will be empty::
238
239 readonly = TextField("Read-Only")
240 readonly.setValue("You can't see this!")
241 readonly.setVisible(False)
242 layout.addComponent(readonly)
243
244 A component is visible only if all of its parents are also visible.
245 If a component is explicitly set to be invisible, changes in the
246 visibility of its parents will not change the visibility of the
247 component.
248
249 @param visible:
250 the boolean value specifying if the component should be
251 visible after the call or not.
252 @see: L{isVisible}
253 """
254 raise NotImplementedError
255
256
258 """Gets the parent component of the component.
259
260 Components can be nested but a component can have only one parent. A
261 component that contains other components, that is, can be a parent,
262 should usually inherit the L{ComponentContainer} interface.
263
264 @return: the parent component
265 @see: L{setParent}
266 """
267 raise NotImplementedError
268
269
271 """Sets the parent component of the component.
272
273 This method automatically calls L{attach} if the parent
274 becomes attached to the application, regardless of whether it was
275 attached previously. Conversely, if the parent is C{None} and
276 the component is attached to the application, L{detach} is
277 called for the component.
278
279 This method is rarely called directly. The
280 L{ComponentContainer.addComponent} method is normally used for adding
281 components to a container and it will call this method implicitly.
282
283 It is not possible to change the parent without first setting the
284 parent to C{None}.
285
286 @param parent:
287 the parent component
288 @raise ValueError:
289 if a parent is given even though the component already has
290 a parent
291 """
292 raise NotImplementedError
293
294
296 """Tests whether the component is in the read-only mode. The user can
297 not change the value of a read-only component. As only L{IField}
298 components normally have a value that can be input or changed by the
299 user, this is mostly relevant only to field components, though not
300 restricted to them.
301
302 Notice that the read-only mode only affects whether the user can
303 change the I{value} of the component; it is possible to, for
304 example, scroll a read-only table.
305
306 The read-only status affects only the user; the value can still be
307 changed programmatically, for example, with L{IProperty.setValue}.
308
309 The method will return C{True} if the component or any of its
310 parents is in the read-only mode.
311
312 @return: C{True} if the component or any of its parents is in
313 read-only mode, C{False} if not.
314 @see: L{setReadOnly}
315 """
316 raise NotImplementedError
317
318
320 """Sets the read-only mode of the component to the specified mode.
321 The user can not change the value of a read-only component.
322
323 As only L{IField} components normally have a value that can be
324 input or changed by the user, this is mostly relevant only to field
325 components, though not restricted to them.
326
327 Notice that the read-only mode only affects whether the user can
328 change the I{value} of the component; it is possible to, for
329 example, scroll a read-only table.
330
331 The read-only status affects only the user; the value can still be
332 changed programmatically, for example, with L{IProperty.setValue}.
333
334 This method will trigger a L{RepaintRequestEvent}.
335
336 @param readOnly:
337 a boolean value specifying whether the component is put
338 read-only mode or not
339 """
340 raise NotImplementedError
341
342
344 """Gets the caption of the component.
345
346 See L{setCaption} for a detailed description of the caption.
347
348 @return: the caption of the component or C{null} if the caption
349 is not set.
350 @see: L{setCaption}
351 """
352 raise NotImplementedError
353
354
356 """Sets the caption of the component.
357
358 A I{caption} is an explanatory textual label accompanying a user
359 interface component, usually shown above, left of, or inside the
360 component. I{Icon} (see L{setIcon} is
361 closely related to caption and is usually displayed horizontally before
362 or after it, depending on the component and the containing layout.
363
364 The caption can usually also be given as the first parameter to a
365 constructor, though some components do not support it::
366
367 area = new RichTextArea()
368 area.setCaption("You can edit stuff here")
369 area.setValue("<h1>Helpful Heading</h1>"
370 + "<p>All this is for you to edit.</p>")
371
372 The contents of a caption are automatically quoted, so no raw XHTML can
373 be rendered in a caption. The validity of the used character encoding,
374 usually UTF-8, is not checked.
375
376 The caption of a component is, by default, managed and displayed by the
377 layout component or component container in which the component is
378 placed. For example, the L{VerticalLayout} component shows the captions
379 left-aligned above the contained components, while the L{FormLayout}
380 component shows the captions on the left side of the vertically laid
381 components, with the captions and their associated components
382 left-aligned in their own columns. The L{CustomComponent} does not
383 manage the caption of its composition root, so if the root component
384 has a caption, it will not be rendered. Some components, such as
385 L{Button} and L{Panel}, manage the caption themselves and display it
386 inside the component.
387
388 This method will trigger a L{RepaintRequestEvent}. A reimplementation
389 should call the superclass implementation.
390
391 @param caption:
392 the new caption for the component. If the caption is
393 C{None}, no caption is shown and it does not normally
394 take any space
395 """
396 raise NotImplementedError
397
398
400 """Gets the icon resource of the component.
401
402 See L{setIcon} for a detailed description of the icon.
403
404 @return: the icon resource of the component or C{None} if the
405 component has no icon
406 @see: L{setIcon}
407 """
408 raise NotImplementedError
409
410
412 """Sets the icon of the component.
413
414 An icon is an explanatory graphical label accompanying a user interface
415 component, usually shown above, left of, or inside the component. Icon
416 is closely related to caption (see L{setCaption})
417 and is usually displayed horizontally before or after it, depending on
418 the component and the containing layout.
419
420 The image is loaded by the browser from a resource, typically a
421 L{ThemeResource}::
422
423 # IComponent with an icon from a custom theme
424 name = TextField("Name")
425 name.setIcon(ThemeResource("icons/user.png"))
426 layout.addComponent(name)
427
428 # IComponent with an icon from another theme ('runo')
429 ok = Button("OK")
430 ok.setIcon(ThemeResource("../runo/icons/16/ok.png"))
431 layout.addComponent(ok)
432
433 The icon of a component is, by default, managed and displayed by the
434 layout component or component container in which the component is
435 placed. For example, the L{VerticalLayout} component shows the icons
436 left-aligned above the contained components, while the L{FormLayout}
437 component shows the icons on the left side of the vertically laid
438 components, with the icons and their associated components left-aligned
439 in their own columns. The L{CustomComponent} does not manage the
440 icon of its composition root, so if the root component has an icon, it
441 will not be rendered.
442
443 An icon will be rendered inside an HTML element that has the
444 C{v-icon} CSS style class. The containing layout may enclose an icon
445 and a caption inside elements related to the caption, such as
446 C{v-caption} .
447
448 This method will trigger a L{RepaintRequestEvent}.
449
450 @param icon:
451 the icon of the component. If null, no icon is shown and it
452 does not normally take any space.
453 @see: L{getIcon}
454 @see: L{setCaption}
455 """
456 raise NotImplementedError
457
458
460 """Gets the parent window of the component.
461
462 If the component is not attached to a window through a component
463 containment hierarchy, C{None} is returned.
464
465 The window can be either an application-level window or a sub-window.
466 If the component is itself a window, it returns a reference to itself,
467 not to its containing window (of a sub-window).
468
469 @return: the parent window of the component or C{None} if it is
470 not attached to a window or is itself a window
471 """
472 raise NotImplementedError
473
474
476 """Gets the application object to which the component is attached.
477
478 The method will return C{None} if the component is not currently
479 attached to an application. This is often a problem in constructors of
480 regular components and in the initializers of custom composite
481 components. A standard workaround is to move the problematic
482 initialization to L{attach}, as described in the documentation of
483 the method.
484
485 @return: the parent application of the component or C{None}.
486 @see: L{attach}
487 """
488 raise NotImplementedError
489
490
492 """Notifies the component that it is connected to an application.
493
494 The caller of this method is L{setParent} if the parent
495 is itself already attached to the application. If not, the parent will
496 call the L{attach} for all its children when it is attached to
497 the application. This method is always called before the component is
498 painted for the first time.
499
500 Reimplementing the C{attach()} method is useful for tasks that need
501 to get a reference to the parent, window, or application object with
502 the L{getParent}, L{getWindow}, and L{getApplication} methods. A
503 component does not yet know these objects in the constructor,
504 so in such case, the methods will return C{None}. For example, the
505 following is invalid::
506
507 class AttachExample(CustomComponent):
508 def __init__(self):
509 # ERROR: We can't access the application object yet.
510 r = ClassResource("smiley.jpg", getApplication())
511 image = Embedded("Image:", r)
512 setCompositionRoot(image)
513
514 Adding a component to an application triggers calling the
515 L{attach} method for the component. Correspondingly, removing a
516 component from a container triggers calling the L{detach} method.
517 If the parent of an added component is already connected to the
518 application, the C{attach()} is called immediately from
519 L{setParent}::
520
521 class AttachExample(CustomComponent):
522 def __init__(self):
523 pass
524
525 def attach(self):
526 super(AttachExample, self).attach() # must call
527
528 # Now we know who ultimately owns us.
529 r = ClassResource("smiley.jpg", self.getApplication())
530 image = Embedded("Image", r)
531 self.setCompositionRoot(image)
532
533 The attachment logic is implemented in L{AbstractComponent}.
534
535 @see: L{getApplication}
536 """
537 raise NotImplementedError
538
539
541 """Notifies the component that it is detached from the application.
542
543 The L{getApplication} and L{getWindow} methods might
544 return C{None} after this method is called.
545
546 The caller of this method is L{setParent} if the parent is in the
547 application. When the parent is detached from the application
548 it is its response to call L{detach} for all the children and to
549 detach itself from the terminal.
550 """
551 raise NotImplementedError
552
553
555 """Gets the locale of the component.
556
557 If a component does not have a locale set, the locale of its parent is
558 returned, and so on. Eventually, if no parent has locale set, the
559 locale of the application is returned. If the application does not have
560 a locale set, it is determined by C{getDefaultLocale()}.
561
562 As the component must be attached before its locale can be acquired,
563 using this method in the internationalization of component captions,
564 etc. is generally not feasible. For such use case, we recommend using
565 an otherwise acquired reference to the application locale.
566
567 @return: Locale of this component or C{null} if the component and
568 none of its parents has a locale set and the component is not
569 yet attached to an application.
570 """
571 raise NotImplementedError
572
573
575 """The child components of the component must call this method when
576 they need repainting. The call must be made even in the case in which
577 the children sent the repaint request themselves.
578
579 A repaint request is ignored if the component is invisible.
580
581 This method is called automatically by L{AbstractComponent}, which
582 also provides a default implementation of it. As this is a somewhat
583 internal feature, it is rarely necessary to reimplement this or call it
584 explicitly.
585
586 @param alreadyNotified:
587 the collection of repaint request listeners that have been
588 already notified by the child. This component should not
589 re-notify the listed listeners again. The container given as
590 parameter must be modifiable as the component might modify
591 it and pass it forward. A C{None} parameter is interpreted
592 as an empty collection.
593 """
594 raise NotImplementedError
595
596
598 """Registers a new (generic) component event listener for the
599 component::
600
601 class Listening(CustomComponent, IListener):
602
603 # Stored for determining the source of an event
604 ok = None
605
606 status = None # For displaying info about the event
607
608 def __init__(self):
609 layout = VerticalLayout()
610
611 # Some miscellaneous component
612 name = TextField("Say it all here")
613 name.addListener(self)
614 name.setImmediate(true)
615 layout.addComponent(name)
616
617 # Handle button clicks as generic events instead
618 # of Button.ClickEvent events
619 ok = new Button("OK")
620 ok.addListener(self)
621 layout.addComponent(ok)
622
623 # For displaying information about an event
624 status = new Label("")
625 layout.addComponent(status)
626
627 setCompositionRoot(layout)
628
629
630 def componentEvent(event):
631 # Act according to the source of the event
632 if (event.getSource() == ok):
633 getWindow().showNotification("Click!")
634
635 status.setValue("Event from " +
636 event.getSource().__class__.__name__
637 + ": " + event.__class__.__name__)
638
639
640 listening = Listening()
641 layout.addComponent(listening)
642
643 @param listener:
644 the new IListener to be registered.
645 @see: L{component.Event}
646 @see: L{removeListener}
647 """
648 raise NotImplementedError
649
650
651 - def addCallback(self, callback, eventType=None, *args):
652 raise NotImplementedError
653
654
656 """Removes a previously registered component event listener from this
657 component.
658
659 @param listener:
660 the listener to be removed.
661 @see: L{addListener}
662 """
663 raise NotImplementedError
664
665
667 raise NotImplementedError
668
669
670 -class Event(EventObject):
671 """Superclass of all component originated events.
672
673 Events are the basis of all user interaction handling in Muntjac. To
674 handle events, you provide a listener object that receives the events of
675 the particular event type::
676
677 Notice that while each of the event types have their corresponding
678 listener types; the listener interfaces are not required to inherit the
679 C{IComponent.IListener} interface.
680
681 @see: L{component.IListener}
682 """
683
685 """Constructs a new event with the specified source component.
686
687 @param source:
688 the source component of the event
689 """
690 super(Event, self).__init__(source)
691
692
694 """Gets the component where the event occurred.
695
696 @return: the source component of the event
697 """
698 return self.getSource()
699
700
702 """IListener interface for receiving C{component.Event}s.
703
704 IListener interfaces are the basis of all user interaction handling in
705 Muntjac. You have or create a listener object that receives the events.
706 All event types have their corresponding listener types; they are not,
707 however, required to inherit the C{component.IListener} interface,
708 and they rarely do so.
709
710 This generic listener interface is useful typically when you wish to
711 handle events from different component types in a single listener method
712 (C{componentEvent()}. If you handle component events in an anonymous
713 listener class, you normally use the component specific listener class,
714 such as L{button.ClickEvent}::
715
716
717 class Listening(CustomComponent, IListener):
718 ok = None # Stored for determining the source of an event
719
720 status = None # For displaying info about the event
721
722 def __init__(self):
723 layout = VerticalLayout()
724
725 # Some miscellaneous component
726 name = TextField("Say it all here")
727 name.addListener(self)
728 name.setImmediate(True)
729 layout.addComponent(name)
730
731 # Handle button clicks as generic events instead
732 # of Button.ClickEvent events
733 ok = new Button("OK")
734 ok.addListener(self)
735 layout.addComponent(ok)
736
737 # For displaying information about an event
738 status = Label("")
739 layout.addComponent(status)
740
741 setCompositionRoot(layout)
742
743
744 def componentEvent(event):
745 # Act according to the source of the event
746 if (event.getSource() == ok
747 and event__class__ == Button.ClickEvent):
748 getWindow().showNotification("Click!")
749
750 # Display source component and event class names
751 status.setValue("Event from " +
752 event.getSource().__class__.__name__
753 + ": " + event.__class__.__name__)
754
755 listening = Listening()
756 layout.addComponent(listening)
757
758 @see: L{IComponent.addListener}
759 """
760
762 """Notifies the listener of a component event.
763
764 As the event can typically come from one of many source components,
765 you may need to differentiate between the event source by component
766 reference, class, etc::
767
768 def componentEvent(event):
769 # Act according to the source of the event
770 if (event.getSource() == ok and
771 event.__class__ == button.ClickEvent):
772 getWindow().showNotification("Click!")
773
774 # Display source component and event class names
775 status.setValue("Event from " +
776 event.getSource().__class__.__name__
777 + ": " + event.__class__.__name__)
778
779 @param event:
780 the event that has occured.
781 """
782 raise NotImplementedError
783
784
786 """Class of all component originated error events.
787
788 The component error event is normally fired by
789 L{AbstractComponent.setComponentError}. The component errors are set
790 by the framework in some situations and can be set by user code. They
791 are indicated in a component with an error indicator.
792 """
793
794 - def __init__(self, message, component):
795 """Constructs a new event with a specified source component.
796
797 @param message:
798 the error message.
799 @param component:
800 the source component.
801 """
802 super(ErrorEvent, self).__init__(component)
803 self._message = message
804
805
807 """Gets the error message.
808
809 @return: the error message.
810 """
811 return self._message
812
813
815 """IListener interface for receiving C{IComponent.Errors}s."""
816
818 """Notifies the listener of a component error.
819
820 @param event:
821 the event that has occured.
822 """
823 raise NotImplementedError
824
825
827 """A sub-interface implemented by components that can obtain input focus.
828 This includes all L{Field} components as well as some other
829 components, such as L{Upload}.
830
831 Focus can be set with L{focus}. This interface does not provide
832 an accessor that would allow finding out the currently focused component;
833 focus information can be acquired for some (but not all) L{Field}
834 components through the L{IFocusListener} and L{IBlurListener} interfaces.
835
836 @see: L{FieldEvents}
837 """
838
840 """Sets the focus to this component::
841
842 loginBox = Form()
843 loginBox.setCaption("Login")
844 layout.addComponent(loginBox)
845
846 # Create the first field which will be focused
847 username = TextField("User name")
848 loginBox.addField("username", username)
849
850 # Set focus to the user name
851 username.focus()
852
853 password = TextField("Password")
854 loginBox.addField("password", password)
855
856 login = Button("Login")
857 loginBox.getFooter().addComponent(login)
858
859 Notice that this interface does not provide an accessor that would
860 allow finding out the currently focused component. Focus information
861 can be acquired for some (but not all) L{IField} components
862 through the L{IFocusListener} and L{IBlurListener} interfaces.
863
864 @see: L{FieldEvents}
865 @see: L{FocusEvent}
866 @see: L{IFocusListener}
867 @see: L{BlurEvent}
868 @see: L{IBlurListener}
869 """
870 raise NotImplementedError
871
872
874 """Gets the I{tabulator index} of the C{IFocusable} component.
875
876 @return: tab index set for the C{IFocusable} component
877 @see: L{setTabIndex}
878 """
879 raise NotImplementedError
880
881
883 """Sets the I{tabulator index} of the C{IFocusable} component.
884 The tab index property is used to specify the order in which the
885 fields are focused when the user presses the Tab key. Components with
886 a defined tab index are focused sequentially first, and then the
887 components with no tab index::
888
889 loginBox = Form()
890 loginBox.setCaption("Login")
891 layout.addComponent(loginBox)
892
893 # Create the first field which will be focused
894 username = TextField("User name")
895 loginBox.addField("username", username)
896
897 # Set focus to the user name
898 username.focus()
899
900 password = TextField("Password")
901 loginBox.addField("password", password)
902
903 login = Button("Login")
904 loginBox.getFooter().addComponent(login)
905
906 # An additional component which natural focus order would
907 # be after the button.
908 remember = CheckBox("Remember me")
909 loginBox.getFooter().addComponent(remember)
910
911 username.setTabIndex(1)
912 password.setTabIndex(2)
913 remember.setTabIndex(3) # Different than natural place
914 login.setTabIndex(4)
915
916 After all focusable user interface components are done, the browser
917 can begin again from the component with the smallest tab index, or it
918 can take the focus out of the page, for example, to the location bar.
919
920 If the tab index is not set (is set to zero), the default tab order
921 is used. The order is somewhat browser-dependent, but generally
922 follows the HTML structure of the page.
923
924 A negative value means that the component is completely removed from
925 the tabulation order and can not be reached by pressing the Tab key
926 at all.
927
928 @param tabIndex:
929 the tab order of this component. Indexes usually start
930 from 1. Zero means that default tab order should be used.
931 A negative value means that the field should not be
932 included in the tabbing sequence.
933 @see: L{getTabIndex}
934 """
935 raise NotImplementedError
936