~ubuntu-branches/ubuntu/utopic/python-traitsui/utopic

« back to all changes in this revision

Viewing changes to examples/tutorials/traitsui_4.0/editors/tabular_editor/tabular_editor.rst

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2011-07-09 13:57:39 UTC
  • Revision ID: james.westby@ubuntu.com-20110709135739-x5u20q86huissmn1
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
The TabularEditor
 
2
=================
 
3
 
 
4
Traits 3.0 introduces a new editor, called the **TabularEditor**, located in the
 
5
*traitsui.wx.extras.tabular_editor* module that can be used for many
 
6
of the same purposes as the existing **TableEditor**. However, while similar in
 
7
function, each editor has its own particular strengths and weaknesses.
 
8
 
 
9
Some of the strengths of the new **TabularEditor** are:
 
10
 
 
11
- **Very fast**. The editor uses a *virtual* model which only accesses data
 
12
  from the underlying data model as needed. For example, if you have a million
 
13
  element array, but can only view 50 rows at a time, the editor will only 
 
14
  request 50 rows at a time.
 
15
  
 
16
- **Very flexible data model**. The editor uses a new adapter model for 
 
17
  interfacing with your underlying data that allows it to easily deal with many
 
18
  types of data representation: from lists of objects, to arrays of numbers, to
 
19
  tuples of tuples, and many other formats as well.
 
20
  
 
21
- **Supports a useful set of data operations**. The editor includes built-in
 
22
  support for a number of useful data operations, including:
 
23
  
 
24
  - Moving the selection up and down using the keyboard arrow keys.
 
25
  - Moving rows up and down using the keyboard arrow keys.
 
26
  - Inserting and deleting rows using the keyboard.
 
27
  - Begin editing table rows using the keyboard.
 
28
  - Drag and drop of table items to and from the editor, including support for
 
29
    both *copy* and *move* operations for single or multiple table items.
 
30
    
 
31
- **Visually appealing**. The editor, in general, uses the underlying OS's
 
32
  native table or grid control, and as a result often looks better than the 
 
33
  control used by the **TableEditor**.
 
34
  
 
35
- **Supports displaying text and images in any cell**. Note however that 
 
36
  the images displayed must all be the same size for optimal results.
 
37
  
 
38
Some of the weaknesses of the **TabularEditor** compared to the **TableEditor**
 
39
are:
 
40
 
 
41
- **Not as full-featured**. The **TableEditor** includes support for arbitrary
 
42
  data filters and searches and different types of data sorting. The differences
 
43
  here may narrow over time as new features get added to the **TabularEditor**.
 
44
  
 
45
- **Limited data editing capabilities**: The **TabularEditor** only supports 
 
46
  editing textual values, unlike the **TableEditor**, which supports a wide 
 
47
  variety of column editors and can be extended with more as needed. This is 
 
48
  due to limitations of the underlying native OS control used by the editor.
 
49
  
 
50
Setting up a **TabularEditor** for use in a Traits UI is divided into two main
 
51
parts:
 
52
 
 
53
- Configuring the **TabularEditor** object.
 
54
- Creating a suitable adapter (or adapters) for use with the editor.
 
55
 
 
56
We'll start off first with a description of the **TabularEditor** class, and
 
57
describe the adapter interface in a later section.
 
58
 
 
59
The TabularEditor Class
 
60
-----------------------
 
61
 
 
62
The **TabularEditor** class defines a large number of traits which are used to
 
63
configure the editor. We'll divide the set of traits into several categories,
 
64
and describe each in turn.
 
65
 
 
66
Visual Traits
 
67
-------------
 
68
    
 
69
show_titles
 
70
    A boolean value which specifies whether or not column headers should be
 
71
    displayed at the top of the table. It defaults to **True**.
 
72
    
 
73
horizontal_lines
 
74
    A boolean value which specifies whether or not horizontal lines should be 
 
75
    drawn between rows in the table. It defaults to **True**.
 
76
    
 
77
vertical_lines
 
78
    A boolean value which specifies whether or not vertical lines should be 
 
79
    drawn between columns in the table. It defaults to **True**.
 
80
    
 
81
Control Traits
 
82
--------------
 
83
    
 
84
editable
 
85
    A boolean value that specifies whether or not the user is allowed to edit
 
86
    data in the table. It defaults to **True**.
 
87
                 
 
88
multi_select
 
89
    A boolean value that specifies whether or not the user is allowed to select
 
90
    multiple rows in the table at once. It defaults to **False**.
 
91
 
 
92
operations
 
93
    A list of strings that specify what operations the user is allowed to
 
94
    perform on items in the table. The possible values are:
 
95
    
 
96
    - **delete**: The user can delete table rows.
 
97
    - **insert**: The user can insert new table rows at any position in the 
 
98
      table.
 
99
    - **append**: The user can append new table rows to the end of the table.
 
100
    - **edit**: The user can edit the contents of table rows.
 
101
    - **move**: The user can move table rows within the table.
 
102
    
 
103
    You should include in the list all operations that you want to allow the
 
104
    user to perform (e.g. *['delete','insert','append']*).
 
105
          
 
106
drag_move
 
107
    A boolean value that specifies whether *drag move* operations are allowed
 
108
    (**True**), or should all drag operations be treated as *drag copy*
 
109
    operations (**False**). The default is **False**.
 
110
           
 
111
adapter
 
112
    An instance of **TabularAdapter** that the editor uses to interface to the
 
113
    underlying **Item** data supplied to the editor. This is normally an
 
114
    instance of a subclass of **TabularAdapter** specially written for the type 
 
115
    of data being edited. This will be described more fully in the 
 
116
    **TabularAdapter** section.
 
117
    
 
118
adapter_name
 
119
    An optional string that specifies the extended trait name of a trait that
 
120
    contains the **TabularAdapter** the editor should used. If the value of the
 
121
    trait changes while the editor is active, the editor will automatically
 
122
    start using the new adapter. Normally you will use either the *adapter*
 
123
    trait *or* the *adapter_name* trait, but not both. However, it is possible 
 
124
    to use both together if needed.
 
125
                       
 
126
images
 
127
    An optional list of **ImageResource** objects describing a set of images 
 
128
    that can be displayed in the table's cells. Specifying a set here allows you
 
129
    to refer to the images by name within the adapter. However, it is also
 
130
    possible for the adapter to supply the **ImageResource** object directly
 
131
    for any image it wants to display.
 
132
 
 
133
Event Handling Traits
 
134
---------------------
 
135
 
 
136
selected
 
137
    An optional string that specifies the extended trait name of a trait that
 
138
    contains the currently selected table items. For a single-select mode
 
139
    editor, this should be a scalar trait, and for a multi-select mode editor,
 
140
    it should be a list trait. The type of the trait should be the same as the
 
141
    type of data being displayed in the table. This trait can be used to both
 
142
    set and get the current table selection.
 
143
    
 
144
selected_row
 
145
    An optional string that specifies the extended trait name of a trait that
 
146
    contains the currently selected table item indices. For a single-select mode
 
147
    editor this should be an **Int** value, and for a multi-select mode editor
 
148
    it should be a **List(Int)** value. This trait can be used to both set and
 
149
    get the current table selection.
 
150
 
 
151
activated    
 
152
    An optional string that specifies the extended trait name of a trait that
 
153
    contains the currently activated table item. It should be an instance of the
 
154
    table item data type. The trait can only be used to get the value of
 
155
    the most recently activated table item. An item is activated either by the
 
156
    user double-clicking on it or by pressing the **Enter** key when the item 
 
157
    is selected.
 
158
     
 
159
activated_row
 
160
    An optional string that specifies the extended trait name of a trait that
 
161
    contains the currently activated table item index. It should be an **Int** 
 
162
    value. The trait can only be used to get the index of the most recently 
 
163
    activated table item. An item is activated either by the user
 
164
    double-clicking on it or by pressing the **Enter** key when the item is
 
165
    selected.
 
166
    
 
167
clicked
 
168
    An optional string that specifies the extended trait name of a trait that
 
169
    contains a **TabularEditorEvent** object containing the information 
 
170
    associated with the most recent left mouse button click within the editor.
 
171
    The trait can only be used to get the **TabularEditorEvent** object. The
 
172
    **TabularEditorEvent** object is described in the next section.
 
173
    
 
174
dclicked
 
175
    An optional string that specifies the extended trait name of a trait that
 
176
    contains a **TabularEditorEvent** object containing the information 
 
177
    associated with the most recent left mouse button double-click within the 
 
178
    editor. The trait can only be used to get the **TabularEditorEvent** 
 
179
    object. The **TabularEditorEvent** object is described in the next section.
 
180
    
 
181
right_clicked
 
182
    An optional string that specifies the extended trait name of a trait that
 
183
    contains a **TabularEditorEvent** object containing the information 
 
184
    associated with the most recent right mouse button click within the editor.
 
185
    The trait can only be used to get the **TabularEditorEvent** object. The
 
186
    **TabularEditorEvent** object is described in the next section.
 
187
    
 
188
right_dclicked
 
189
    An optional string that specifies the extended trait name of a trait that
 
190
    contains a **TabularEditorEvent** object containing the information 
 
191
    associated with the most recent right mouse button double-click within the 
 
192
    editor. The trait can only be used to get the **TabularEditorEvent** 
 
193
    object. The **TabularEditorEvent** object is described in the next section.
 
194
 
 
195
The TabularEditorEvent Class
 
196
----------------------------
 
197
 
 
198
Objects of the **TabularEditorEvent** class contain information related to a 
 
199
mouse button click that occurs within the editor. The class has no methods, 
 
200
but does define the following traits:
 
201
 
 
202
row
 
203
    An integer specifying the index of the table item that was clicked on.
 
204
    
 
205
column
 
206
    A value specifying the column id of the table cell that was clicked on.
 
207
    This value will correspond to the second element of the tuple used to
 
208
    define the column in the **TabularEditor** adapter supplied to the editor. 
 
209
    This will be described in a later section.
 
210
    
 
211
item
 
212
    The data item corresponding to the table row that was clicked on. The type
 
213
    of this data will depend upon the type of data contained in the underlying
 
214
    data model.
 
215
    
 
216
The TabularEditor User Interface
 
217
--------------------------------
 
218
 
 
219
Depending upon how you have configured the **TabularEditor** and its associated
 
220
adapter, the following user interface features may be available:
 
221
 
 
222
- **Up arrow**: Move the selection up one line.
 
223
- **Down arrow**: Move the selection down one line.
 
224
- **Page down**: Append a new item to the end of the list (*'append'*).
 
225
- **Left arrow**: Move the current selection up one line (*'move'*).
 
226
- **Right arrow**: Move the current selection down one line (*'move'*).
 
227
- **Backspace, Delete**: Delete all items in the current selection from the 
 
228
  list (*'delete'*).
 
229
- **Enter, Escape**: Edit the current selection (*'edit'*).
 
230
- **Insert**: Insert a new item before the current selection (*'insert'*).
 
231
 
 
232
In the preceding list, the values in parentheses refer to the operation that
 
233
must be included in the **TabularEditor** *operations* trait in order for the 
 
234
specified key to have any effect.
 
235
 
 
236
The *append*, *move*, *edit* and *insert* operations are only available if a
 
237
single item is selected. The *delete* operation works when the selection has
 
238
one or more items.
 
239
 
 
240
Depending upon how the **TabularEditor** and adapter are specified, drag and
 
241
drop operations may also be available. If multiple items are selected and the
 
242
user drags one of the selected items, all selected items will be included in
 
243
the drag operation. If the user drags a non-selected item, only that item will
 
244
be dragged.
 
245
 
 
246
The editor also supports both *drag-move* and *drag-copy* semantics. A
 
247
*drag-move* operation means that the dragged items will be sent to the target
 
248
and removed from the list data. A *drag-copy* operation means that the
 
249
dragged items will be sent to the target, but will *not* be deleted from the
 
250
**Item** data. Note that in a *drag-copy* operation, if you do not want the
 
251
target to receive the same data contained in the list, then you must return a
 
252
copy or clone of the data when the editor requests the drag data from the
 
253
adapter.
 
254
 
 
255
You can prevent *drag-move* operations by making sure that the 
 
256
**TabularEditor** *drag_move* trait is set to **False** (the default).
 
257
 
 
258
Note that the default operation when a user begins a drag operation is
 
259
*drag_move*. A *drag-copy* operation occurs when the user also holds the
 
260
*Ctrl* key down during the drag operation (the mouse pointer changes to indicate
 
261
the change in drag semantics). If *drag_move* operations are disabled by
 
262
setting the **TabularEditor** *drag_move* trait to **False**, any *drag-move*
 
263
operation is automatically treated as a *drag_copy*.
 
264
 
 
265
The tabular editor only allows the user to edit the first column of data in the
 
266
table (a restriction imposed by the underlying OS widget). If the *'edit'* 
 
267
operation is enabled, the user can begin editing the first column either by 
 
268
clicking on the row twice, or by selecting the row and pressing the **Enter** or 
 
269
**Escape** key.
 
270
 
 
271
Finally, the user can resize columns in the table by dragging the column title
 
272
dividers left or right with the mouse. Once resized in this manner, the column
 
273
remains that size until the user resizes the column again. This is true
 
274
even if you assigned a dynamic width to the column (see the **TabularAdapter**
 
275
section for more information about what this means). If the user wants to allow
 
276
a previously user-sized column to be restored to its original developer
 
277
specified size again, they must right-click on the column title to *release* 
 
278
its user specified size and restore its original size. 
 
279
 
 
280
If you enable *persistence* for the editor by specifying a non-empty *id* trait
 
281
for the editor's **Item** and **View** objects, any user specified column 
 
282
widths will be saved across application sessions.
 
283
 
 
284
The TabularAdapter Class
 
285
------------------------
 
286
 
 
287
The power and flexibility of the tabular editor is mostly a result of the
 
288
**TabularAdapter** class, which is the base class from which all tabular editor
 
289
adapters must be derived.
 
290
 
 
291
The **TabularEditor** object interfaces between the underlying toolkit widget
 
292
and your program, while the **TabularAdapter** object associated with the
 
293
editor interfaces between the editor and your data.
 
294
 
 
295
The design of the **TabularAdapter** base class is such that it tries to make
 
296
simple cases simple and complex cases possible. How it accomplishes this is what
 
297
we'll be discussing in the following sections.
 
298
 
 
299
The TabularAdapter *columns* Trait
 
300
----------------------------------
 
301
 
 
302
First up is the **TabularAdapter** *columns* trait, which is a list of values
 
303
which define, in presentation order, the set of columns to be displayed by the
 
304
associated **TabularEditor**.
 
305
 
 
306
Each entry in the *columns* list can have one of two forms: 
 
307
 
 
308
- string 
 
309
- ( string, any )
 
310
 
 
311
where *string* is the user interface name of the column (which will appear in
 
312
the table column header) and *any* is any value that you want to use to 
 
313
identify that column to your adapter. Normally this value is either a trait name 
 
314
or an integer index value, but it can be any value you want. If only *string*
 
315
is specified, then *any* is the index of the *string* within *columns*.
 
316
 
 
317
For example, say you want to display a table containing a list of tuples, each
 
318
of which has three values: a name, an age, and a weight. You could then use
 
319
the following value for the *columns* trait::
 
320
 
 
321
    columns = [ 'Name', 'Age', 'Weight' ]
 
322
    
 
323
By default, the *any* values (also referred to in later sections as the 
 
324
*column ids*) for the columns will be the corresponding tuple index values.
 
325
 
 
326
Say instead that you have a list of **Person** objects, with *name*, *age* and
 
327
*weight* traits that you want to display in the table. Then you could use the
 
328
following *columns* value instead::
 
329
 
 
330
    columns = [ ( 'Name',   'name' ), 
 
331
                ( 'Age',    'age' ),
 
332
                ( 'Weight', 'weight' ) ]
 
333
                
 
334
In this case, the *column ids* are the names of the traits you want to display
 
335
in each column.
 
336
 
 
337
Note that it is possible to dynamically modify the contents of the *columns*
 
338
trait while the **TabularEditor** is active. The **TabularEditor** will 
 
339
automatically modify the table to show the new set of defined columns.
 
340
 
 
341
The Core TabularAdapter Interface
 
342
---------------------------------
 
343
 
 
344
In this section, we'll describe the core interface to the **TabularAdapter**
 
345
class. This is the actual interface used by the **TabularEditor** to access your
 
346
data and display attributes. In the most complex data representation cases, 
 
347
these are the methods that you must override in order to have the greatest
 
348
control over what the editor sees and does. 
 
349
 
 
350
However, the base **TabularAdapter** class provides default implementations for 
 
351
all of these methods. In subsequent sections, we'll look at how these default 
 
352
implementations provide simple means  of customizing the adapter to your needs.
 
353
But for now, let's start by covering the details of the core interface itself.
 
354
 
 
355
To reduce the amount of repetition, we'll use the following definitions in all 
 
356
of the method argument lists that follow in this section:
 
357
 
 
358
object
 
359
    The object whose trait is being edited by the **TabularEditor**.
 
360
    
 
361
trait
 
362
    The name of the trait the **TabularEditor** is editing.
 
363
    
 
364
row
 
365
    The row index (starting with 0) of a table item. 
 
366
    
 
367
column
 
368
    The column index (starting with 0) of a table column.
 
369
 
 
370
The adapter interface consists of a number of methods which can be divided into
 
371
two main categories: those which are sensitive to the type of a particular table
 
372
item, and those which are not. We'll begin with the methods that are
 
373
sensitive to an item's type:
 
374
 
 
375
get_alignment ( object, trait, column )
 
376
    Returns the alignment style to use for a specified column. 
 
377
    
 
378
    The possible values that can be returned are: *'left'*, *'center'* or
 
379
    *'right'*. All table items share the same alignment for a specified column.
 
380
 
 
381
get_width ( object, trait, column )
 
382
    Returns the width to use for a specified column. The result can either be a
 
383
    float or integer value. 
 
384
    
 
385
    If the value is <= 0, the column will have a *default* width, which is the 
 
386
    same as specifying a width of *0.1*. 
 
387
    
 
388
    If the value is > 1.0, it is converted to an integer and the result is
 
389
    the width of the column in pixels. This is referred to as a *fixed width*
 
390
    column.
 
391
    
 
392
    If the value is a float such that 0.0 < value <= 1.0, it is treated as the 
 
393
    *unnormalized fraction of the available space* that is to be assigned to the
 
394
    column. What this means requires a little explanation. 
 
395
    
 
396
    To arrive at the size in pixels of the column at any given time, the editor
 
397
    adds together all of the *unnormalized fraction* values returned for all
 
398
    columns in the table to arrive at a total value. Each 
 
399
    *unnormalized fraction* is then divided by the total to create a 
 
400
    *normalized fraction*. Each column is then assigned an amount of space in 
 
401
    pixels equal to the maximum of 30 or its *normalized fraction* multiplied 
 
402
    by the *available space*. The *available space* is defined as the actual 
 
403
    width of the table minus the width of all *fixed width* columns. Note that 
 
404
    this calculation is performed each time the table is resized in the user 
 
405
    interface, thus allowing columns of this type to increase or decrease their
 
406
    width dynamically, while leaving *fixed width* columns unchanged.
 
407
        
 
408
get_can_edit ( object, trait, row )
 
409
    Returns a boolean value indicating whether the user can edit a specified 
 
410
    *object.trait[row]* item. 
 
411
    
 
412
    A **True** result indicates that the value can be edited, while a **False**
 
413
    result indicates that it cannot.
 
414
    
 
415
get_drag ( object, trait, row )
 
416
    Returns the value to be *dragged* for a specified *object.trait[row]* item. 
 
417
    A result of **None** means that the item cannot be dragged. Note that the
 
418
    value returned does not have to be the actual row item. It can be any
 
419
    value that you want to drag in its place. In particular, if you want the
 
420
    drag target to receive a copy of the row item, you should return a copy or
 
421
    clone of the item in its place.
 
422
    
 
423
    Also note that if multiple items are being dragged, and this method returns
 
424
    **None** for any item in the set, no drag operation is performed.
 
425
        
 
426
get_can_drop ( object, trait, row, value )
 
427
    Returns whether the specified *value* can be dropped on the specified 
 
428
    *object.trait[row]* item. A value of **True** means the *value* can be 
 
429
    dropped; and a value of **False** indicates that it cannot be dropped.
 
430
    
 
431
    The result is used to provide the user positive or negative drag feedback 
 
432
    while dragging items over the table. *Value* will always be a single value,
 
433
    even if multiple items are being dragged. The editor handles multiple drag
 
434
    items by making a separate call to *get_can_drop* for each item being
 
435
    dragged.
 
436
        
 
437
get_dropped ( object, trait, row, value )
 
438
    Returns how to handle a specified *value* being dropped on a specified 
 
439
    *object.trait[row]* item. The possible return values are:
 
440
                
 
441
    - **'before'**: Insert the specified *value* before the dropped on item.
 
442
    - **'after'**: Insert the specified *value* after the dropped on item.
 
443
    
 
444
    Note there is no result indicating *do not drop* since you will have already
 
445
    indicated that the *object* can be dropped by the result returned from a 
 
446
    previous call to *get_can_drop*.
 
447
        
 
448
get_font ( object, trait, row )
 
449
    Returns the font to use for displaying a specified *object.trait[row]* item.
 
450
    
 
451
    A result of **None** means use the default font; otherwise a **wx.Font**
 
452
    object should be returned. Note that all columns for the specified table row
 
453
    will use the font value returned.
 
454
        
 
455
get_text_color ( object, trait, row )
 
456
    Returns the text color to use for a specified *object.trait[row]* item. 
 
457
    
 
458
    A result of **None** means use the default text color; otherwise a 
 
459
    **wx.Colour** object should be returned. Note that all columns for the 
 
460
    specified table row will use the text color value returned. 
 
461
     
 
462
get_bg_color ( object, trait, row )
 
463
    Returns the background color to use for a specified *object.trait[row]*
 
464
    item. 
 
465
    
 
466
    A result of **None** means use the default background color; otherwise a
 
467
    **wx.Colour** object should be returned. Note that all columns for the 
 
468
    specified table row will use the background color value returned.
 
469
        
 
470
get_image ( object, trait, row, column )
 
471
    Returns the image to display for a specified *object.trait[row].column* 
 
472
    item. 
 
473
    
 
474
    A result of **None** means no image will be displayed in the specified table
 
475
    cell. Otherwise the result should either be the name of the image, or an 
 
476
    **ImageResource** object specifying the image to display. 
 
477
    
 
478
    A name is allowed in the case where the image is specified in the 
 
479
    **TabularEditor** *images* trait. In that case, the name should be the same 
 
480
    as the string specified in the **ImageResource** constructor.
 
481
     
 
482
get_format ( object, trait, row, column )
 
483
    Returns the Python formatting string to apply to the specified 
 
484
    *object.trait[row].column* item in order to display it in the table.
 
485
    
 
486
    The result can be any Python string containing exactly one Python formatting
 
487
    sequence, such as *'%.4f'* or *'(%5.2f)'*.
 
488
     
 
489
get_text ( object, trait, row, column )
 
490
    Returns a string containing the text to display for a specified 
 
491
    *object.trait[row].column* item.
 
492
    
 
493
    If the underlying data representation for a specified item is not a string,
 
494
    then it is your responsibility to convert it to one before returning it as
 
495
    the result.
 
496
     
 
497
set_text ( object, trait, row, text ):
 
498
    Sets the value for the specified *object.trait[row].column* item to the 
 
499
    string specified by *text*. 
 
500
    
 
501
    If the underlying data does not store the value as text, it is your 
 
502
    responsibility to convert *text* to the correct representation used. This 
 
503
    method is called when the user completes an editing operation on a table 
 
504
    cell.
 
505
        
 
506
get_tooltip ( object, trait, row, column )
 
507
    Returns a string containing the tooltip to display for a specified 
 
508
    *object.trait[row].column* item. 
 
509
    
 
510
    You should return the empty string if you do not wish to display a tooltip.
 
511
 
 
512
The following are the remaining adapter methods, which are not sensitive to the
 
513
type of item or column data:
 
514
    
 
515
get_item ( object, trait, row )
 
516
    Returns the specified *object.trait[row]* item.
 
517
    
 
518
    The value returned should be the value that exists (or *logically* exists)
 
519
    at the specified *row* in your data. If your data is not really a list or
 
520
    array, then you can just use *row* as an integer *key* or *token* that
 
521
    can be used to retrieve a corresponding item. The value of *row* will 
 
522
    always be in the range: 0 <= row < *len( object, trait )* (i.e. the result
 
523
    returned by the adapter *len* method).
 
524
    
 
525
len ( object, trait )
 
526
    Returns the number of row items in the specified *object.trait* list.
 
527
    
 
528
    The result should be an integer greater than or equal to 0.
 
529
        
 
530
delete ( object, trait, row )
 
531
    Deletes the specified *object.trait[row]* item. 
 
532
    
 
533
    This method is only called if the *delete* operation is specified in the 
 
534
    **TabularEditor** *operation* trait, and the user requests that the item be
 
535
    deleted from the table. The adapter can still choose not to delete the 
 
536
    specified item if desired, although that may prove confusing to the user.
 
537
        
 
538
insert ( object, trait, row, value )
 
539
    Inserts *value* at the specified *object.trait[row]* index. The specified
 
540
    *value* can be:
 
541
    
 
542
    - An item being moved from one location in the data to another.
 
543
    - A new item created by a previous call to *get_default_value*.
 
544
    - An item the adapter previously approved via a call to *get_can_drop*.
 
545
    
 
546
    The adapter can still choose not to insert the item into the data, although
 
547
    that may prove confusing to the user.
 
548
    
 
549
get_default_value ( object, trait )
 
550
    Returns a new default value for the specified *object.trait* list. 
 
551
    
 
552
    This method is called when *insert* or *append* operations are allowed and
 
553
    the user requests that a new item be added to the table. The result should
 
554
    be a new instance of whatever underlying representation is being used for
 
555
    table items.
 
556
 
 
557
Creating a Custom TabularAdapter
 
558
--------------------------------
 
559
 
 
560
Having just taken a look at the core **TabularAdapter** interface, you might now
 
561
be thinking that there are an awful lot of methods that need to be specified to 
 
562
get an adapter up and running. But as we mentioned earlier, **TabularAdapter**
 
563
is not an abstract base class. It is a concrete base class with implementations
 
564
for each of the methods in its interface. And the implementations are written
 
565
in such a way that you will hopefully hardly ever need to override them.
 
566
 
 
567
In this section, we'll explain the general implementation style used by these
 
568
methods, and how you can take advantage of them in creating your own adapters.
 
569
 
 
570
One of the things you probably noticed as you read through the core adapter
 
571
interface section is that most of the methods have names of the form:
 
572
*get_xxx* or *set_xxx*, which is similar to the familiar *getter/setter* pattern
 
573
used when defining trait properties. The adapter interface is purposely defined 
 
574
this way so that it can expose and leverage a simple set of design rules.
 
575
 
 
576
The design rules are followed consistently in the implementations of all of the
 
577
adapter methods described in the first section of the core adapter interface, so
 
578
that once you understand how they work, you can easily apply the design pattern
 
579
to all items in that section. Then, only in the case where the design rules will
 
580
not work for your application will you ever have to override any of those 
 
581
**TabularAdapter** base class method implementations.
 
582
 
 
583
So the first thing to understand is that if an adapter method name has the form:
 
584
*get_xxx* or *set_xxx* it really is dealing with some kind of trait called 
 
585
*xxx*, or which contains *xxx* in its name. For example, the *get_alignment* 
 
586
method retrieves the value of some *alignment* trait defined on the adapter.
 
587
In the following discussion we'll simply refer to an attribute name generically 
 
588
as *attribute*, but you will need to replace it by an actual attribute name 
 
589
(e.g. *alignment*) in your adapter.
 
590
 
 
591
The next thing to keep in mind is that the adapter interface is designed to
 
592
easily deal with items that are not all of the same type. As we just said, the
 
593
design rules apply to all adapter methods in the first group, which were
 
594
defined as methods which are sensitive to an item's type. Item type sensitivity 
 
595
plays an important part in the design rules, as we will see shortly.
 
596
 
 
597
With this in mind, we now describe the simple design rules used by the first
 
598
group of methods in the **TabularAdapter** class:
 
599
 
 
600
- When getting or setting an adapter attribute, the method first retrieves the 
 
601
  underlying item for the specified data row. The item, and type (i.e. class) of
 
602
  the item, are then used in the next rule.
 
603
  
 
604
- The method gets or sets the first trait it finds on the adapter that matches 
 
605
  one of the following names:
 
606
  
 
607
  - *classname_columnid_attribute*
 
608
  - *classsname_attribute*
 
609
  - *columnid_attribute*
 
610
  - *attribute*
 
611
 
 
612
  where:
 
613
  
 
614
  - *classname* is the name of the class of the item found in the first step, or
 
615
    one of its base class names, searched in the order defined by the *mro*
 
616
    (**method resolution order**) for the item's class.
 
617
  - *columnid* is the column id specified by the developer in the adapter's
 
618
    *column* trait for the specified table column.
 
619
  - *attribute* is the attribute name as described previously (e.g. 
 
620
    *alignment*).
 
621
    
 
622
Note that this last rule always finds a matching trait, since the 
 
623
**TabularAdapter** base class provides traits that match the simple *attribute*
 
624
form for all attributes these rules apply to. Some of these are simple traits, 
 
625
while others are properties. We'll describe the behavior of all these *default*
 
626
traits shortly.
 
627
    
 
628
The basic idea is that rather than override the first group of core adapter 
 
629
methods, you simply define one or more simple traits or trait properties on your
 
630
**TabularAdapter** subclass that provide or accept the specified information. 
 
631
 
 
632
All of the adapter methods in the first group provide a number of arguments,
 
633
such as *object*, *trait*, *row* and *column*. In order to define a trait 
 
634
property, which cannot be passed this information directly, the adapter always 
 
635
stores the arguments and values it computes in the following adapter traits, 
 
636
where they can be easily accessed by a trait getter or setter method:
 
637
 
 
638
- *row*: The table row being accessed.
 
639
- *column*: The column id of the table column being accessed (not its index).
 
640
- *item*: The data item for the specified table row (i.e. the item determined
 
641
  in the first step described above).
 
642
- *value*: In the case of a *set_xxx* method, the value to be set; otherwise it
 
643
  is **None**.
 
644
 
 
645
As mentioned previously, the **TabularAdapter** class provides trait definitions 
 
646
for all of the attributes these rules apply to. You can either use the
 
647
default values as they are, override the default, set a new value, or completely 
 
648
replace the trait definition in a subclass. A description of the default trait
 
649
implementation for each attribute is as follows:
 
650
 
 
651
default_value = Any( '' )
 
652
    The default value for a new row. 
 
653
    
 
654
    The default value is the empty string, but you will normally need to assign 
 
655
    a different (default) value.
 
656
   
 
657
format = Str( '%s' )
 
658
    The default Python formatting string for a column item.
 
659
    
 
660
    The default value is *'%s'* which will simply convert the column item to a
 
661
    displayable string value.
 
662
    
 
663
text = Property
 
664
    The text to display for the column item.
 
665
    
 
666
    The implementation of the property checks the type of the column's
 
667
    *column id*:
 
668
    
 
669
    - If it is an integer, it returns *format%item[column_id]*.
 
670
    - Otherwise, it returns *format%item.column_id*.
 
671
    
 
672
    Note that *format* refers to the value returned by a call to *get_format*
 
673
    for the current column item.
 
674
    
 
675
text_color = Property
 
676
    The text color for a row item. 
 
677
    
 
678
    The property implementation checks to see if the current table row is even
 
679
    or odd, and based on the result returns the value of the *even_text_color* 
 
680
    or *odd_text_color* trait if the value is not **None**, and the value of the
 
681
    *default_text_color* trait if it is. The definition of these additional 
 
682
    traits are as follows:
 
683
    
 
684
    - odd_text_color = Color( None )
 
685
    - even_text_color = Color( None )
 
686
    - default_text_color = Color( None )
 
687
    
 
688
    Remember that a **None** value means use the default text color.
 
689
    
 
690
bg_color = Property
 
691
    The background color for a row item. 
 
692
    
 
693
    The property implementation checks to see if the current table row is even
 
694
    or odd, and based on the result returns the value of the *even_bg_color* or
 
695
    *odd_bg_color* trait if the value is not **None**, and the value of the 
 
696
    *default_bg_color* trait if it is. The definition of these additional 
 
697
    traits are as follows:
 
698
    
 
699
    - odd_bg_color = Color( None )
 
700
    - even_bg_color = Color( None )
 
701
    - default_bg_color = Color( None )
 
702
    
 
703
    Remember that a **None** value means use the default background color.
 
704
    
 
705
alignment = Enum( 'left', 'center', 'right' )
 
706
    The alignment to use for a specified column.
 
707
    
 
708
    The default value is *'left'*.
 
709
    
 
710
width = Float( -1 )
 
711
    The width of a specified column.
 
712
    
 
713
    The default value is *-1*, which means a dynamically sized column with an
 
714
    *unnormalized fractional* value of *0.1*.
 
715
    
 
716
can_edit = Bool( True )
 
717
    Specifies whether the text value of the current item can be edited.
 
718
    
 
719
    The default value is **True**, which means that the user can edit the value.
 
720
    
 
721
drag = Property
 
722
    A property which returns the value to be dragged for a specified row item.
 
723
    
 
724
    The property implementation simply returns the current row item.
 
725
    
 
726
can_drop = Bool( False )
 
727
    Specifies whether the specified value be dropped on the current item.
 
728
    
 
729
    The default value is **False**, meaning that the value cannot be dropped.
 
730
    
 
731
dropped = Enum( 'after', 'before' )
 
732
    Specifies where a dropped item should be placed in the table relative to
 
733
    the item it is dropped on.
 
734
    
 
735
    The default value is *'after'*.
 
736
    
 
737
font = Font
 
738
    The font to use for the current item.
 
739
    
 
740
    The default value is the standard default Traits font value.
 
741
    
 
742
image = Str( None )
 
743
    The name of the default image to use for a column.
 
744
    
 
745
    The default value is **None**, which means that no image will be displayed
 
746
    for the column.
 
747
    
 
748
    # The text of a row/column item:
 
749
    text = Property
 
750
    
 
751
tooltip = Str
 
752
    The tooltip information for a column item.
 
753
    
 
754
    The default value is the empty string, which means no tooltip information
 
755
    will be displayed for the column.
 
756
 
 
757
The preceding discussion applies to all of the methods defined in the first 
 
758
group of **TabularAdapter** interface methods. However, the design rules do not 
 
759
apply to the remaining five adapter methods, although they all provide a useful
 
760
default implementation:
 
761
    
 
762
get_item ( object, trait, row )
 
763
    Returns the value of the *object.trait[row]* item.
 
764
    
 
765
    The default implementation assumes the trait defined by *object.trait* is a
 
766
    *sequence* and attempts to return the value at index *row*. If an error
 
767
    occurs, it returns **None** instead. This definition should work correctly
 
768
    for lists, tuples and arrays, or any other object that is indexable, but
 
769
    will have to be overridden for all other cases. 
 
770
    
 
771
    Note that this method is the one called in the first design rule described
 
772
    previously to retrieve the item at the current table row.
 
773
    
 
774
len ( object, trait )
 
775
    Returns the number of items in the specified *object.trait* list.
 
776
    
 
777
    Again, the default implementation assumes the trait defined by 
 
778
    *object.trait* is a *sequence* and attempts to return the result of calling
 
779
    *len( object.trait )*. It will need to be overridden for any type of data
 
780
    which for which *len* will not work.
 
781
        
 
782
delete ( object, trait, row )
 
783
    Deletes the specified *object.trait[row]* item.
 
784
    
 
785
    The default implementation assumes the trait defined by *object.trait* is a
 
786
    mutable sequence and attempts to perform a *del object.trait[row]*
 
787
    operation.
 
788
        
 
789
insert ( object, trait, row, value )
 
790
    Inserts a new value at the specified *object.trait[row]* index.
 
791
    
 
792
    The default implementation assumes the trait defined by *object.trait* is a
 
793
    mutable sequence and attempts to perform an *object.trait[row:row]=[value]*
 
794
    operation.
 
795
    
 
796
get_default_value ( object, trait )
 
797
    Returns a new default value for the specified *object.trait* list.
 
798
    
 
799
    The default implementation simply returns the value of the adapter's
 
800
    *default_value* trait.
 
801
    
 
802
A TabularAdapter Example
 
803
------------------------
 
804
 
 
805
Having now learned about the core adapter interface as well as the design rules
 
806
supported by the default method implementations, you're probably wondering how
 
807
you can use a **TabularAdapter** for creating a real user interface.
 
808
 
 
809
So in this section we'll cover a simple example of creating a **TabularAdapter**
 
810
subclass to try and show how all of the pieces fit together.
 
811
 
 
812
In subsequent tutorials, we'll provide complete examples of creating
 
813
user interfaces using both the **TabularEditor** and **TabularAdapter** in 
 
814
combination.
 
815
 
 
816
For this example, let's assume we have the following two classes::
 
817
 
 
818
    class Person ( HasTraits ):
 
819
    
 
820
        name    = Str
 
821
        age     = Int
 
822
        address = Str
 
823
        
 
824
    class MarriedPerson ( Person ):
 
825
    
 
826
        partner = Instance( Person )
 
827
    
 
828
where **Person** represents a single person, and **MarriedPerson** represents
 
829
a married person and is derived from **Person** but adds the *partner* trait to
 
830
reference the person they are married to.
 
831
 
 
832
Now, assume we also have the following additional class::
 
833
 
 
834
    class Report ( HasTraits ):
 
835
    
 
836
        people = List( Person )
 
837
    
 
838
which has a *people* trait which contains a list of both **Person** and
 
839
**MarriedPerson** objects, and we want to create a tabular display showing the
 
840
following information:
 
841
 
 
842
- Name of the person
 
843
- Age of the person
 
844
- The person's address
 
845
- The name of the person's spouse (if any)
 
846
 
 
847
In addition:
 
848
 
 
849
- We want to use a Courier 10 point font for each line in the table.
 
850
- We want the age column to be right, instead of left, justified
 
851
- If the person is a minor (age < 18) and married, we want to show a red flag
 
852
  image in the age column.
 
853
- If the person is married, we want to make the background color for that row
 
854
  a light blue.
 
855
 
 
856
Given this set of requirements, we can now define the following
 
857
**TabularAdapter** subclass::
 
858
 
 
859
    class ReportAdapter ( TabularAdapter ):
 
860
    
 
861
        columns = [ ( 'Name',    'name' ), 
 
862
                    ( 'Age',     'age' ), 
 
863
                    ( 'Address', 'address' )
 
864
                    ( 'Spouse',  'spouse' ) ]
 
865
                    
 
866
        font                      = 'Courier 10'
 
867
        age_alignment             = Constant( 'right' )
 
868
        MarriedPerson_age_image   = Property
 
869
        MarriedPerson_bg_color    = Color( 0xE0E0FF )
 
870
        MarriedPerson_spouse_text = Property
 
871
        Person_spouse_text        = Constant( '' )
 
872
        
 
873
        def _get_MarriedPerson_age_image ( self ):
 
874
            if self.item.age < 18:
 
875
                return 'red_flag'
 
876
            return None
 
877
            
 
878
        def _get_MarriedPerson_spouse_text ( self ):
 
879
            return self.item.partner.name
 
880
        
 
881
Hopefully, this simple example conveys some of the power and flexibility that 
 
882
the **TabularAdapter** class provides you. But, just in case it doesn't, let's 
 
883
go over some of the more interesting details:
 
884
 
 
885
- Note the values in the *columns* trait. The first three values define 
 
886
  *column ids* which map directly to traits defined on our data objects, while
 
887
  the last one defines an arbitrary string which we define so that we can
 
888
  reference it in the *MarriedPerson_spouse_text* and *Person_spouse_text* trait
 
889
  definitions.
 
890
  
 
891
- Since the font we want to use applies to all table rows, we just specify a
 
892
  new default value for the existing **TabularAdapter** *font* trait.
 
893
  
 
894
- Since we only want to override the default left alignment for the age column,
 
895
  we simply define an *age_alignment* trait as a constant *'right'* value. We
 
896
  could have also used *age_alignment = Str('right')*, but *Constant* never
 
897
  requires storage to be used in an object.
 
898
  
 
899
- We define the *MarriedPerson_age_image* property to handle putting the
 
900
  *red flag* image in the age column. By including the class name of the items
 
901
  it applies to, we only need to check the *age* value in determining what
 
902
  value to return.
 
903
  
 
904
- Similary, we use the *MarriedPerson_bg_color* trait to ensure that each
 
905
  **MarriedPerson** object has the correct background color in the table.
 
906
  
 
907
- Finally, we use the *MarriedPerson_spouse_text* and *Person_spouse_text*
 
908
  traits, one a property and the other a simple constant value, to determine 
 
909
  what text to display in the *Spouse* column for the different object types. 
 
910
  Note that even though a **MarriedPerson** is both a **Person** and a
 
911
  **MarriedPerson**, it will correctly use the *MarriedPerson_spouse_text* trait
 
912
  since the search for a matching trait is always made in *mro* order.
 
913
  
 
914
Although this is completely subjective, some of the things that the author
 
915
feels stand out about this approach are:
 
916
 
 
917
- The class definition is short and sweet. Less code is good.
 
918
- The bulk of the code is declarative. Less room for logic errors.
 
919
- There is only one bit of logic in the class (the *if* statement in the
 
920
  *MarriedPerson_age_image* property implementation). Again, less logic usually
 
921
  translates into more reliable code).
 
922
- The defined traits and even the property implementation method names read 
 
923
  very descriptively. *_get_MarriedPerson_age_image* pretty much says what you 
 
924
  would write in a comment or doc string. The implementation almost is the
 
925
  documentation.
 
926
 
 
927
Look for a complete traits UI example based on this sample problem definition in 
 
928
the *Single and Married Person Example* tutorial in this section.
 
929
  
 
930
Now, as the complexity of a tabular view increases, the definition of the
 
931
**TabularAdapter** class could possibly start to get large and unwieldy. At
 
932
this point we could begin refactoring our design to use the **ITabularAdapter**
 
933
interface and **AnITabularAdapter** implementation class to create 
 
934
*sub-adapters* that can be added to our **TabularAdapter** subclass to extend
 
935
its functionality even further. Creating sub-adapters and adding them via the 
 
936
**TabularAdapter** *adapters* trait is a topic covered in a follow-on tutorial.
 
937