1
#------------------------------------------------------------------------------
2
# Copyright (c) 2007, Riverbank Computing Limited
5
# This software is provided without warranty under the terms of the BSD license.
6
# However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply
9
# Author: Riverbank Computing Limited
10
#------------------------------------------------------------------------------
12
""" Defines the base class for PyQt editors.
15
#-------------------------------------------------------------------------------
17
#-------------------------------------------------------------------------------
19
from pyface.qt import QtGui
22
import HasTraits, Instance, Str, Callable
25
import Editor as UIEditor
28
import OKColor, ErrorColor
30
#-------------------------------------------------------------------------------
32
#-------------------------------------------------------------------------------
34
class Editor ( UIEditor ):
35
""" Base class for PyQt editors for Traits-based UIs.
38
def clear_layout(self):
39
""" Delete the contents of a control's layout.
41
layout = self.control.layout()
43
itm = layout.takeAt(0)
47
itm.widget().setParent(None)
49
#---------------------------------------------------------------------------
50
# Handles the 'control' trait being set:
51
#---------------------------------------------------------------------------
53
def _control_changed ( self, control ):
54
""" Handles the **control** trait being set.
56
# FIXME: Check we actually make use of this.
57
if control is not None:
58
control._editor = self
60
#---------------------------------------------------------------------------
61
# Assigns focus to the editor's underlying toolkit widget:
62
#---------------------------------------------------------------------------
64
def set_focus ( self ):
65
""" Assigns focus to the editor's underlying toolkit widget.
67
if self.control is not None:
68
self.control.setFocus()
70
#---------------------------------------------------------------------------
71
# Updates the editor when the object trait changes external to the editor:
72
#---------------------------------------------------------------------------
74
def update_editor ( self ):
75
""" Updates the editor when the object trait changes externally to the
78
new_value = self.str_value
79
if self.control.text() != new_value:
80
self.control.setText( new_value )
82
#---------------------------------------------------------------------------
83
# Handles an error that occurs while setting the object's trait value:
84
#---------------------------------------------------------------------------
86
def error ( self, excp ):
87
""" Handles an error that occurs while setting the object's trait value.
89
# Make sure the control is a widget rather than a layout.
90
if isinstance(self.control, QtGui.QLayout):
91
control = self.control.parentWidget()
93
control = self.control
95
QtGui.QMessageBox.information(control,
96
self.description + ' value error', str(excp))
98
#---------------------------------------------------------------------------
99
# Sets the tooltip for a specified control:
100
#---------------------------------------------------------------------------
102
def set_tooltip ( self, control = None ):
103
""" Sets the tooltip for a specified control.
105
desc = self.description
107
desc = self.object.base_trait( self.name ).desc
111
desc = 'Specifies ' + desc
114
control = self.control
116
control.setToolTip( desc )
120
#---------------------------------------------------------------------------
121
# Handles the 'enabled' state of the editor being changed:
122
#---------------------------------------------------------------------------
124
def _enabled_changed(self, enabled):
125
"""Handles the **enabled** state of the editor being changed.
127
if self.control is not None:
128
self._enabled_changed_helper(self.control, enabled)
130
def _enabled_changed_helper(self, control, enabled):
131
"""A helper that allows the control to be a layout and recursively
132
manages all its widgets.
134
if isinstance(control, QtGui.QWidget):
135
control.setEnabled(enabled)
137
for i in range(control.count()):
138
itm = control.itemAt(i)
139
self._enabled_changed_helper((itm.widget() or itm.layout()),
142
#---------------------------------------------------------------------------
143
# Handles the 'visible' state of the editor being changed:
144
#---------------------------------------------------------------------------
146
def _visible_changed(self, visible):
147
"""Handles the **visible** state of the editor being changed.
149
if self.label_control is not None:
150
self.label_control.setVisible(visible)
152
self._visible_changed_helper(self.control, visible)
154
# FIXME: Does PyQt need something similar?
155
# Handle the case where the item whose visibility has changed is a
157
#page = self.control.GetParent()
158
#page_name = getattr( page, '_page_name', '' )
160
# notebook = page.GetParent()
161
# for i in range( 0, notebook.GetPageCount() ):
162
# if notebook.GetPage( i ) is page:
169
# notebook.AddPage( page, page_name )
172
# notebook.RemovePage( i )
174
def _visible_changed_helper(self, control, visible):
175
"""A helper that allows the control to be a layout and recursively
176
manages all its widgets.
178
if isinstance(control, QtGui.QWidget):
179
control.setVisible(visible)
181
for i in range(control.count()):
182
itm = control.itemAt(i)
183
self._visible_changed_helper((itm.widget() or itm.layout()),
186
#---------------------------------------------------------------------------
187
# Returns the editor's control for indicating error status:
188
#---------------------------------------------------------------------------
190
def get_error_control ( self ):
191
""" Returns the editor's control for indicating error status.
195
#---------------------------------------------------------------------------
196
# Returns whether or not the editor is in an error state:
197
#---------------------------------------------------------------------------
199
def in_error_state ( self ):
200
""" Returns whether or not the editor is in an error state.
204
#---------------------------------------------------------------------------
205
# Sets the editor's current error state:
206
#---------------------------------------------------------------------------
208
def set_error_state ( self, state = None, control = None ):
209
""" Sets the editor's current error state.
213
state = state or self.in_error_state()
216
control = self.get_error_control()
218
if not isinstance( control, list ):
219
control = [ control ]
222
pal = QtGui.QPalette(item.palette())
226
if getattr( item, '_ok_color', None ) is None:
227
item._ok_color = QtGui.QColor(pal.color(QtGui.QPalette.Base))
229
color = getattr( item, '_ok_color', OKColor )
231
pal.setColor(QtGui.QPalette.Base, color)
234
#---------------------------------------------------------------------------
235
# Handles the editor's invalid state changing:
236
#---------------------------------------------------------------------------
238
def _invalid_changed ( self, state ):
239
""" Handles the editor's invalid state changing.
241
self.set_error_state()
243
#-------------------------------------------------------------------------------
244
# 'EditorWithList' class:
245
#-------------------------------------------------------------------------------
247
class EditorWithList ( Editor ):
248
""" Editor for an object that contains a list.
250
#---------------------------------------------------------------------------
252
#---------------------------------------------------------------------------
254
# Object containing the list being monitored
255
list_object = Instance( HasTraits )
257
# Name of the monitored trait
260
# Function used to evaluate the current list object value:
261
list_value = Callable
263
#---------------------------------------------------------------------------
264
# Initializes the object:
265
#---------------------------------------------------------------------------
267
def init ( self, parent ):
268
""" Initializes the object.
270
factory = self.factory
273
self.list_object, self.list_name, self.list_value = \
274
self.parse_extended_name( name )
276
self.list_object, self.list_name = factory, 'values'
277
self.list_value = lambda: factory.values
279
self.list_object.on_trait_change( self._list_updated,
280
self.list_name, dispatch = 'ui' )
284
#---------------------------------------------------------------------------
285
# Disconnects the listeners set up by the constructor:
286
#---------------------------------------------------------------------------
288
def dispose ( self ):
289
""" Disconnects the listeners set up by the constructor.
291
self.list_object.on_trait_change( self._list_updated,
292
self.list_name, remove = True )
294
super( EditorWithList, self ).dispose()
296
#---------------------------------------------------------------------------
297
# Handles the monitored trait being updated:
298
#---------------------------------------------------------------------------
300
def _list_updated ( self ):
301
""" Handles the monitored trait being updated.
303
self.list_updated( self.list_value() )
305
#---------------------------------------------------------------------------
306
# Handles the monitored list being updated:
307
#---------------------------------------------------------------------------
309
def list_updated ( self, values ):
310
""" Handles the monitored list being updated.
312
raise NotImplementedError
314
#-------------------------------------------------------------------------------
315
# 'EditorFromView' class:
316
#-------------------------------------------------------------------------------
318
class EditorFromView ( Editor ):
319
""" An editor generated from a View object.
322
#---------------------------------------------------------------------------
323
# Initializes the object:
324
#---------------------------------------------------------------------------
326
def init ( self, parent ):
327
""" Initializes the object.
329
self._ui = ui = self.init_ui( parent )
330
if ui.history is None:
331
ui.history = self.ui.history
333
self.control = ui.control
335
#---------------------------------------------------------------------------
336
# Creates and returns the traits UI defined by this editor:
337
# (Must be overridden by a subclass):
338
#---------------------------------------------------------------------------
340
def init_ui ( self, parent ):
341
""" Creates and returns the traits UI defined by this editor.
342
(Must be overridden by a subclass).
344
raise NotImplementedError
346
#---------------------------------------------------------------------------
347
# Updates the editor when the object trait changes external to the editor:
348
#---------------------------------------------------------------------------
350
def update_editor ( self ):
351
""" Updates the editor when the object trait changes externally to the
354
# Normally nothing needs to be done here, since it should all be handled
355
# by the editor's internally created traits UI:
358
#---------------------------------------------------------------------------
359
# Dispose of the editor:
360
#---------------------------------------------------------------------------
362
def dispose ( self ):
363
""" Disposes of the editor.
367
super( EditorFromView, self ).dispose()