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

« back to all changes in this revision

Viewing changes to traitsui/view.py

  • 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
#------------------------------------------------------------------------------
 
2
#
 
3
#  Copyright (c) 2005, Enthought, Inc.
 
4
#  All rights reserved.
 
5
#
 
6
#  This software is provided without warranty under the terms of the BSD
 
7
#  license included in enthought/LICENSE.txt and may be redistributed only
 
8
#  under the conditions described in the aforementioned license.  The license
 
9
#  is also available online at http://www.enthought.com/licenses/BSD.txt
 
10
#
 
11
#  Thanks for using Enthought open source!
 
12
#
 
13
#  Author: David C. Morrill
 
14
#  Date:   10/07/2004
 
15
#
 
16
#------------------------------------------------------------------------------
 
17
 
 
18
""" Defines the View class used to represent the structural content of a
 
19
    Traits-based user interface.
 
20
"""
 
21
 
 
22
#-------------------------------------------------------------------------------
 
23
#  Imports:
 
24
#-------------------------------------------------------------------------------
 
25
 
 
26
from __future__ import absolute_import
 
27
 
 
28
from traits.api import (Any, Bool, Callable, Enum, Event, Float, Instance, List, Str,
 
29
    Trait, TraitPrefixList)
 
30
 
 
31
from .view_element import ViewElement, ViewSubElement
 
32
 
 
33
from .ui import UI
 
34
 
 
35
from .ui_traits import (AButton, ATheme, AnObject, Buttons, DockStyle,
 
36
    EditorStyle, ExportType, HelpId, Image, SequenceTypes, ViewStatus)
 
37
 
 
38
from .handler import Handler, default_handler
 
39
 
 
40
from .group import Group
 
41
 
 
42
from .item import Item
 
43
 
 
44
from .include import Include
 
45
 
 
46
#-------------------------------------------------------------------------------
 
47
#  Trait definitions:
 
48
#-------------------------------------------------------------------------------
 
49
 
 
50
# Name of the view trait:
 
51
AnId = Str( desc = 'the name of the view' )
 
52
 
 
53
# Contents of the view trait (i.e., a single Group object):
 
54
Content = Instance( Group, desc = 'the content of the view' )
 
55
 
 
56
# An optional model/view factory for converting the model into a viewable
 
57
# 'model_view' object
 
58
AModelView = Callable( desc = 'the factory function for converting a model '
 
59
                              'into a model/view object' )
 
60
 
 
61
# Reference to a Handler object trait:
 
62
AHandler = Any( desc = 'the handler for the view' )
 
63
 
 
64
# Dialog window title trait:
 
65
ATitle = Str( desc = 'the window title for the view' )
 
66
 
 
67
# Dialog window icon trait
 
68
#icon_trait = Instance( 'pyface.image_resource.ImageResource',
 
69
#                     desc = 'the ImageResource of the icon file for the view' )
 
70
 
 
71
# User interface 'kind' trait. The values have the following meanings:
 
72
#
 
73
# * 'panel': An embeddable panel. This type of window is intended to be used as
 
74
#   part of a larger interface.
 
75
# * 'subpanel': An embeddable panel that does not display command buttons,
 
76
#   even if the View specifies them.
 
77
# * 'modal': A modal dialog box that operates on a clone of the object until
 
78
#   the user commits the change.
 
79
# * 'nonmodal':  A nonmodal dialog box that operates on a clone of the object
 
80
#   until the user commits the change
 
81
# * 'live': A nonmodal dialog box that immediately updates the object.
 
82
# * 'livemodal': A modal dialog box that immediately updates the object.
 
83
# * 'popup': A temporary, frameless popup dialog that immediately updates the
 
84
#   object and is active only while the mouse pointer is in the dialog.
 
85
# * 'info': A temporary, frameless popup dialog that immediately updates the
 
86
#   object and is active only while the dialog is still over the invoking
 
87
#   control.
 
88
# * 'wizard': A wizard modal dialog box. A wizard contains a sequence of
 
89
#   pages, which can be accessed by clicking **Next** and **Back** buttons.
 
90
#   Changes to attribute values are applied only when the user clicks the
 
91
#   **Finish** button on the last page.
 
92
AKind = Trait( 'live', TraitPrefixList(
 
93
                   'panel', 'subpanel', 'modal', 'nonmodal', 'livemodal',
 
94
                   'live', 'popup', 'popover', 'info', 'wizard' ),
 
95
               desc = 'the kind of view window to create',
 
96
               cols = 4 )
 
97
 
 
98
# Apply changes handler:
 
99
OnApply = Callable( desc = 'the routine to call when modal changes are applied '
 
100
                           'or reverted' )
 
101
 
 
102
# Is the dialog window resizable?
 
103
IsResizable = Bool( False, desc = 'whether dialog can be resized or not' )
 
104
 
 
105
# Is the view scrollable?
 
106
IsScrollable = Bool( False, desc = 'whether view should be scrollable or not' )
 
107
 
 
108
# The valid categories of imported elements that can be dragged into the view:
 
109
ImportTypes = List( Str, desc = 'the categories of elements that can be '
 
110
                                'dragged into the view' )
 
111
 
 
112
# The view position and size traits:
 
113
Width       = Float( -1E6, desc = 'the width of the view window' )
 
114
Height      = Float( -1E6, desc = 'the height of the view window' )
 
115
XCoordinate = Float( -1E6, desc = 'the x coordinate of the view window' )
 
116
YCoordinate = Float( -1E6, desc = 'the y coordinate of the view window' )
 
117
 
 
118
# The result that should be returned if the user clicks the window or dialog
 
119
# close button or icon
 
120
CloseResult = Enum( None, True, False,
 
121
                    desc = 'the result to return when the user clicks the '
 
122
                           'window or dialog close button or icon' )
 
123
 
 
124
# The KeyBindings trait:
 
125
AKeyBindings = Instance( 'traitsui.key_bindings.KeyBindings',
 
126
                         desc = 'the global key bindings for the view' )
 
127
 
 
128
#-------------------------------------------------------------------------------
 
129
#  'View' class:
 
130
#-------------------------------------------------------------------------------
 
131
 
 
132
class View ( ViewElement ):
 
133
    """ A Traits-based user interface for one or more objects.
 
134
 
 
135
        The attributes of the View object determine the contents and layout of
 
136
        an attribute-editing window. A View object contains a set of Group,
 
137
        Item, and Include objects. A View object can be an attribute of an
 
138
        object derived from HasTraits, or it can be a standalone object.
 
139
    """
 
140
 
 
141
    #---------------------------------------------------------------------------
 
142
    #  Trait definitions:
 
143
    #---------------------------------------------------------------------------
 
144
 
 
145
    # A unique identifier for the view:
 
146
    id = AnId
 
147
 
 
148
    # The top-level Group object for the view:
 
149
    content = Content
 
150
 
 
151
    # The menu bar for the view. Usually requires a custom **handler**:
 
152
    menubar = Any # Instance( pyface.action.MenuBarManager )
 
153
 
 
154
    # The toolbar for the view. Usually requires a custom **handler**:
 
155
    toolbar = Any # Instance( pyface.action.ToolBarManager )
 
156
 
 
157
    # Status bar items to add to the view's status bar. The value can be:
 
158
    #
 
159
    #   - **None**: No status bar for the view (the default).
 
160
    #   - string: Same as [ StatusItem( name = string ) ].
 
161
    #   - StatusItem: Same as [ StatusItem ].
 
162
    #   - [ [StatusItem|string], ... ]: Create a status bar with one field for
 
163
    #     each StatusItem in the list (or tuple). The status bar fields are
 
164
    #     defined from left to right in the order specified. A string value is
 
165
    #     converted to: StatusItem( name = string ):
 
166
    statusbar = ViewStatus
 
167
 
 
168
    # List of button actions to add to the view. The **traitsui.menu**
 
169
    # module defines standard buttons, such as **OKButton**, and standard sets
 
170
    # of buttons, such as **ModalButtons**, which can be used to define a value
 
171
    # for this attribute. This value can also be a list of button name strings,
 
172
    # such as ``['OK', 'Cancel', 'Help']``. If set to the empty list, the
 
173
    # view contains a default set of buttons (equivalent to **LiveButtons**:
 
174
    # Undo/Redo, Revert, OK, Cancel, Help). To suppress buttons in the view,
 
175
    # use the **NoButtons** variable, defined in **traitsui.menu**.
 
176
    buttons = Buttons
 
177
 
 
178
    # The default button to activate when Enter is pressed. If not specified,
 
179
    # pressing Enter will not activate any button.
 
180
    default_button = AButton
 
181
 
 
182
    # The set of global key bindings for the view. Each time a key is pressed
 
183
    # while the view has keyboard focus, the key is checked to see if it is one
 
184
    # of the keys recognized by the KeyBindings object. If it is, the matching
 
185
    # KeyBinding's method name is checked to see if it is defined on any of the
 
186
    # object's in the view's context. If it is, the method is invoked. If the
 
187
    # result of the method is **False**, then the search continues with the
 
188
    # next object in the context. If any invoked method returns a non-False
 
189
    # value, processing stops and the key is marked as having been handled. If
 
190
    # all invoked methods return **False**, or no matching KeyBinding object is
 
191
    # found, the key is processed normally. If the view has a non-empty *id*
 
192
    # trait, the contents of the **KeyBindings** object will be saved as part
 
193
    # of the view's persistent data:
 
194
    key_bindings = AKeyBindings
 
195
 
 
196
    # The Handler object that provides GUI logic for handling events in the
 
197
    # window. Set this attribute only if you are using a custom Handler. If
 
198
    # not set, the default Traits UI Handler is used.
 
199
    handler = AHandler
 
200
 
 
201
    # The factory function for converting a model into a model/view object:
 
202
    model_view = AModelView
 
203
 
 
204
    # Title for the view, displayed in the title bar when the view appears as a
 
205
    # secondary window (i.e., dialog or wizard). If not specified, "Edit
 
206
    # properties" is used as the title.
 
207
    title = ATitle
 
208
 
 
209
    # The name of the icon to display in the dialog window title bar:
 
210
    icon = Any
 
211
 
 
212
    # The kind of user interface to create:
 
213
    kind = AKind
 
214
 
 
215
    # The default object being edited:
 
216
    object = AnObject
 
217
 
 
218
    # The default editor style of elements in the view:
 
219
    style = EditorStyle
 
220
 
 
221
    # The default docking style to use for sub-groups of the view. The following
 
222
    # values are possible:
 
223
    #
 
224
    # * 'fixed': No rearrangement of sub-groups is allowed.
 
225
    # * 'horizontal': Moveable elements have a visual "handle" to the left by
 
226
    #   which the element can be dragged.
 
227
    # * 'vertical': Moveable elements have a visual "handle" above them by
 
228
    #   which the element can be dragged.
 
229
    # * 'tabbed': Moveable elements appear as tabbed pages, which can be
 
230
    #   arranged within the window or "stacked" so that only one appears at
 
231
    #   at a time.
 
232
    dock = DockStyle
 
233
 
 
234
    # The image to display on notebook tabs:
 
235
    image = Image
 
236
 
 
237
    # Called when modal changes are applied or reverted:
 
238
    on_apply = OnApply
 
239
 
 
240
    # Can the user resize the window?
 
241
    resizable = IsResizable
 
242
 
 
243
    # Can the user scroll the view? If set to True, window-level scroll bars
 
244
    # appear whenever the window is too small to show all of its contents at
 
245
    # one time. If set to False, the window does not scroll, but individual
 
246
    # widgets might still contain scroll bars.
 
247
    scrollable = IsScrollable
 
248
 
 
249
    # The category of exported elements:
 
250
    export = ExportType
 
251
 
 
252
    # The valid categories of imported elements:
 
253
    imports = ImportTypes
 
254
 
 
255
    # External help context identifier, which can be used by a custom help
 
256
    # handler. This attribute is ignored by the default help handler.
 
257
    help_id = HelpId
 
258
 
 
259
    # Requested x-coordinate (horizontal position) for the view window. This
 
260
    # attribute can be specified in the following ways:
 
261
    #
 
262
    # * A positive integer: indicates the number of pixels from the left edge
 
263
    #   of the screen to the left edge of the window.
 
264
    # * A negative integer: indicates the number of pixels from the right edge
 
265
    #   of the screen to the right edge of the window.
 
266
    # * A floating point value between 0 and 1: indicates the fraction of the
 
267
    #   total screen width between the left edge of the screen and the left edge
 
268
    #   of the window.
 
269
    # * A floating point value between -1 and 0: indicates the fraction of the
 
270
    #   total screen width between the right edge of the screen and the right
 
271
    #   edge of the window.
 
272
    x = XCoordinate
 
273
 
 
274
    # Requested y-coordinate (vertical position) for the view window. This
 
275
    # attribute behaves exactly like the **x** attribute, except that its value
 
276
    # indicates the position of the top or bottom of the view window relative
 
277
    # to the top or bottom of the screen.
 
278
    y = YCoordinate
 
279
 
 
280
    # Requested width for the view window, as an (integer) number of pixels, or
 
281
    # as a (floating point) fraction of the screen width.
 
282
    width = Width
 
283
 
 
284
    # Requested height for the view window, as an (integer) number of pixels, or
 
285
    # as a (floating point) fraction of the screen height.
 
286
    height = Height
 
287
 
 
288
    # Class of dropped objects that can be added:
 
289
    drop_class = Any
 
290
 
 
291
    # Event when the view has been updated:
 
292
    updated = Event
 
293
 
 
294
    # What result should be returned if the user clicks the window or dialog
 
295
    # close button or icon?
 
296
    close_result = CloseResult
 
297
 
 
298
    # The default theme to use for a contained item:
 
299
    item_theme = ATheme
 
300
 
 
301
    # The default theme to use for a contained item's label:
 
302
    label_theme = ATheme
 
303
 
 
304
    # Note: Group objects delegate their 'object' and 'style' traits to the View
 
305
 
 
306
    #-- Deprecated Traits (DO NOT USE) -----------------------------------------
 
307
 
 
308
    ok     = Bool( False )
 
309
    cancel = Bool( False )
 
310
    undo   = Bool( False )
 
311
    redo   = Bool( False )
 
312
    apply  = Bool( False )
 
313
    revert = Bool( False )
 
314
    help   = Bool( False )
 
315
 
 
316
    #---------------------------------------------------------------------------
 
317
    #  Initializes the object:
 
318
    #---------------------------------------------------------------------------
 
319
 
 
320
    def __init__ ( self, *values, **traits ):
 
321
        """ Initializes the object.
 
322
        """
 
323
        ViewElement.__init__( self, **traits )
 
324
        self.set_content( *values )
 
325
 
 
326
    #---------------------------------------------------------------------------
 
327
    #  Sets the content of a view:
 
328
    #---------------------------------------------------------------------------
 
329
 
 
330
    def set_content ( self, *values ):
 
331
        """ Sets the content of a view.
 
332
        """
 
333
        content = []
 
334
        accum   = []
 
335
        for value in values:
 
336
            if isinstance( value, ViewSubElement ):
 
337
                content.append( value )
 
338
            elif type( value ) in SequenceTypes:
 
339
                content.append( Group( *value ) )
 
340
            elif (isinstance( value, basestring ) and
 
341
                 (value[:1] == '<') and (value[-1:] == '>')):
 
342
                # Convert string to an Include value:
 
343
                content.append( Include( value[1:-1].strip() ) )
 
344
            else:
 
345
                content.append( Item( value ) )
 
346
 
 
347
        # If there are any 'Item' objects in the content, wrap the content in a
 
348
        # Group:
 
349
        for item in content:
 
350
            if isinstance( item, Item ):
 
351
                content = [ Group( *content ) ]
 
352
                break
 
353
 
 
354
        # Wrap all of the content up into a Group and save it as our content:
 
355
        self.content = Group( container = self, *content )
 
356
 
 
357
    #---------------------------------------------------------------------------
 
358
    #  Creates a UI user interface object:
 
359
    #---------------------------------------------------------------------------
 
360
 
 
361
    def ui ( self, context, parent        = None, kind       = None,
 
362
                            view_elements = None, handler    = None,
 
363
                            id            = '',   scrollable = None,
 
364
                            args          = None ):
 
365
        """ Creates a **UI** object, which generates the actual GUI window or
 
366
        panel from a set of view elements.
 
367
 
 
368
        Parameters
 
369
        ----------
 
370
        context : object or dictionary
 
371
            A single object or a dictionary of string/object pairs, whose trait
 
372
            attributes are to be edited. If not specified, the current object is
 
373
            used.
 
374
        parent : window component
 
375
            The window parent of the View object's window
 
376
        kind : string
 
377
            The kind of window to create. See the **AKind** trait for details.
 
378
            If *kind* is unspecified or None, the **kind** attribute of the
 
379
            View object is used.
 
380
        view_elements : ViewElements object
 
381
            The set of Group, Item, and Include objects contained in the view.
 
382
            Do not use this parameter when calling this method directly.
 
383
        handler : Handler object
 
384
            A handler object used for event handling in the dialog box. If
 
385
            None, the default handler for Traits UI is used.
 
386
        id : string
 
387
            A unique ID for persisting preferences about this user interface,
 
388
            such as size and position. If not specified, no user preferences
 
389
            are saved.
 
390
        scrollable : Boolean
 
391
            Indicates whether the dialog box should be scrollable. When set to
 
392
            True, scroll bars appear on the dialog box if it is not large enough
 
393
            to display all of the items in the view at one time.
 
394
 
 
395
        """
 
396
        handler = handler or self.handler or default_handler()
 
397
        if not isinstance( handler, Handler ):
 
398
            handler = handler()
 
399
 
 
400
        if args is not None:
 
401
            handler.set( **args )
 
402
 
 
403
        if not isinstance( context, dict ):
 
404
            context = context.trait_context()
 
405
 
 
406
        context.setdefault( 'handler', handler )
 
407
        handler = context[ 'handler' ]
 
408
 
 
409
        if self.model_view is not None:
 
410
            context[ 'object' ] = self.model_view( context[ 'object' ] )
 
411
 
 
412
        self_id = self.id
 
413
        if self_id != '':
 
414
            if id != '':
 
415
                id = '%s:%s' % ( self_id, id )
 
416
            else:
 
417
                id = self_id
 
418
 
 
419
        if scrollable is None:
 
420
            scrollable = self.scrollable
 
421
 
 
422
        ui = UI( view          = self,
 
423
                 context       = context,
 
424
                 handler       = handler,
 
425
                 view_elements = view_elements,
 
426
                 title         = self.title,
 
427
                 id            = id,
 
428
                 scrollable    = scrollable )
 
429
 
 
430
        if kind is None:
 
431
            kind = self.kind
 
432
 
 
433
        ui.ui( parent, kind )
 
434
 
 
435
        return ui
 
436
 
 
437
    #---------------------------------------------------------------------------
 
438
    #  Replaces any items which have an 'id' with an Include object with the
 
439
    #  same 'id', and puts the object with the 'id' into the specified
 
440
    #  ViewElements object:
 
441
    #---------------------------------------------------------------------------
 
442
 
 
443
    def replace_include ( self, view_elements ):
 
444
        """ Replaces any items that have an ID with an Include object with
 
445
            the same ID, and puts the object with the ID into the specified
 
446
            ViewElements object.
 
447
        """
 
448
        if self.content is not None:
 
449
            self.content.replace_include( view_elements )
 
450
 
 
451
    #---------------------------------------------------------------------------
 
452
    #  Returns a 'pretty print' version of the View:
 
453
    #---------------------------------------------------------------------------
 
454
 
 
455
    def __repr__ ( self ):
 
456
        """ Returns a "pretty print" version of the View.
 
457
        """
 
458
        if self.content is None:
 
459
            return '()'
 
460
        return "( %s )" %  ', '.join(
 
461
               [ item.__repr__() for item in self.content.content ] )
 
462