/usr/share/pyshared/kiwi/ui/proxywidget.py is in python-kiwi 1.9.22-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | #
# Kiwi: a Framework and Enhanced Widgets for Python
#
# Copyright (C) 2003-2005 Async Open Source
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
# Author(s): Christian Reis <kiko@async.com.br>
# Lorenzo Gil Sanchez <lgs@sicem.biz>
# Gustavo Rahal <gustavo@async.com.br>
# Johan Dahlin <jdahlin@async.com.br>
# Daniel Saran R. da Cunha <daniel@async.com.br>
#
"""Basic classes for widget support for the Kiwi Framework"""
import gettext
import gobject
import gtk
from gtk import gdk
from kiwi import ValueUnset
from kiwi.component import implements
from kiwi.datatypes import ValidationError, converter, BaseConverter
from kiwi.environ import environ
from kiwi.interfaces import IProxyWidget, IValidatableProxyWidget
from kiwi.log import Logger
from kiwi.ui.gadgets import FadeOut
from kiwi.utils import gsignal, gproperty
log = Logger('widget proxy')
_ = lambda m: gettext.dgettext('kiwi', m)
class _PixbufConverter(BaseConverter):
type = gdk.Pixbuf
name = 'Pixbuf'
def as_string(self, value, format='png'):
buffer = []
value.save_to_callback(buffer.append, format)
string = ''.join(buffer)
return string
def from_string(self, value, format='png'):
loader = gdk.PixbufLoader(format)
try:
loader.write(value)
loader.close()
except gobject.GError, e:
raise ValidationError(_("Could not load image: %s") % e)
pixbuf = loader.get_pixbuf()
return pixbuf
converter.add(_PixbufConverter)
class ProxyWidgetMixin(object):
"""This class is a mixin that provide a common interface for KiwiWidgets.
Usually the Proxy class need to set and get data from the widgets. It also
need a validation framework.
@cvar allowed_data_types: A list of types which we are allowed to use
in this class.
"""
implements(IProxyWidget)
gsignal('content-changed')
gsignal('validation-changed', bool)
gsignal('validate', object, retval=object)
gproperty('data-type', object, blurb='Data Type')
gproperty('model-attribute', str, blurb='Model attribute')
allowed_data_types = ()
# To be able to call the as/from_string without setting the data_type
# property and still receiving a good warning.
_converter = None
def __init__(self):
if not type(self.allowed_data_types) == tuple:
raise TypeError("%s.allowed_data_types must be a tuple" % (
self.allowed_data_types))
self._data_format = None
self._converter_options = {}
# Properties
def prop_set_data_type(self, data_type):
"""Set the data type for the widget
@param data_type: can be None, a type object or a string with the
name of the type object, so None, "<type 'str'>"
or 'str'
"""
if data_type is None:
return data_type
# This may convert from string to type,
# A type object will always be returned
data_type = converter.check_supported(data_type)
if not issubclass(data_type, self.allowed_data_types):
raise TypeError(
"%s only accept %s types, not %r"
% (self,
' or '.join([t.__name__ for t in self.allowed_data_types]),
data_type))
self._converter = converter.get_converter(data_type)
return data_type
# Public API
def set_data_format(self, format):
self._data_format = format
def set_options_for_datatype(self, datatype, **options):
"""Set some options to be passed to the datatype converter.
Any additional parameter will be passed the the converter when
converting an object to a string, for displaying in the widget. Note
that the converter.as_string method should be able to handle such
parameters.
@param datatype: the datatype.
"""
if not options:
raise ValueError
self._converter_options[datatype] = options
def read(self):
"""Get the content of the widget.
The type of the return value
@returns: None if the user input a invalid value
@rtype: Must matche the data-type property.
"""
raise NotImplementedError
def update(self, value):
"""
Update the content value of the widget.
@param value:
"""
raise NotImplementedError
# Private
def _as_string(self, data):
"""Convert a value to a string
@param data: data to convert
"""
conv = self._converter
if conv is None:
conv = converter.get_converter(str)
return conv.as_string(data, format=self._data_format,
**self._converter_options.get(conv.type,{}))
def _from_string(self, data):
"""Convert a string to the data type of the widget
This may raise a L{kiwi.datatypes.ValidationError} if conversion
failed
@param data: data to convert
"""
conv = self._converter
if conv is None:
conv = converter.get_converter(str)
return conv.from_string(data)
VALIDATION_ICON_WIDTH = 16
MANDATORY_ICON = gtk.STOCK_EDIT
ERROR_ICON = gdk.pixbuf_new_from_file(
environ.find_resource('pixmap', 'validation-error-16.png'))
class ValidatableProxyWidgetMixin(ProxyWidgetMixin):
"""Class used by some Kiwi Widgets that need to support mandatory
input and validation features such as custom validation and data-type
validation.
Mandatory support provides a way to warn the user when input is necessary.
The validatation feature provides a way to check the data entered and to
display information about what is wrong.
"""
implements(IValidatableProxyWidget)
gproperty('mandatory', bool, default=False)
def __init__(self, widget=None):
ProxyWidgetMixin.__init__(self)
self._valid = True
self._fade = FadeOut(self)
self._fade.connect('color-changed', self._on_fadeout__color_changed)
# Override in subclass
def update_background(self, color):
"Implement in subclass"
def get_background(self):
"Implement in subclass"
def set_pixbuf(self, pixbuf):
"Implement in subclass"
def get_icon_window(self):
"Implement in subclass"
def set_tooltip(self, text):
"Implement in subclass"
# Public API
def is_valid(self):
"""
Verify the widget state.
@returns: True if the widget is in validated state
"""
return self._valid
def validate(self, force=False):
"""Checks if the data is valid.
Validates data-type and custom validation.
@param force: if True, force validation
@returns: validated data or ValueUnset if it failed
"""
# If we're not visible or sensitive return a blank value, except
# when forcing the validation
if not force and (not self.get_property('visible') or
not self.get_property('sensitive')):
return ValueUnset
try:
data = self.read()
log.debug('Read %r for %s' % (data, self.model_attribute))
# check if we should draw the mandatory icon
# this need to be done before any data conversion because we
# we don't want to end drawing two icons
if self.mandatory and (data == None or
data == '' or
data == ValueUnset):
self.set_blank()
return ValueUnset
else:
# The widgets themselves have now valid the data
# Next step is to call the application specificed
# checks, which are found in the view.
if data is not None and data is not ValueUnset:
# this signal calls the on_widgetname__validate method
# of the view class and gets the exception (if any).
error = self.emit("validate", data)
if error:
raise error
self.set_valid()
return data
except ValidationError, e:
self.set_invalid(str(e))
return ValueUnset
def set_valid(self):
"""Changes the validation state to valid, which will remove icons and
reset the background color
"""
log.debug('Setting state for %s to VALID' % self.model_attribute)
self._set_valid_state(True)
self._fade.stop()
self.set_pixbuf(None)
def set_invalid(self, text=None, fade=True):
"""Changes the validation state to invalid.
@param text: text of tooltip of None
@param fade: if we should fade the background
"""
log.debug('Setting state for %s to INVALID' % self.model_attribute)
self._set_valid_state(False)
# If there is no error text, set a generic one so the error icon
# still have a tooltip
if not text:
text = _("'%s' is not a valid value for this field") % self.read()
self.set_tooltip(text)
if not fade:
self.set_pixbuf(ERROR_ICON)
self.update_background(gtk.gdk.color_parse(self._fade.ERROR_COLOR))
return
# When the fading animation is finished, set the error icon
# We don't need to check if the state is valid, since stop()
# (which removes this timeout) is called as soon as the user
# types valid data.
def done(fadeout, c):
self.set_pixbuf(ERROR_ICON)
self.queue_draw()
fadeout.disconnect(c.signal_id)
class SignalContainer:
pass
c = SignalContainer()
c.signal_id = self._fade.connect('done', done, c)
if self._fade.start(self.get_background()):
self.set_pixbuf(None)
def set_blank(self):
"""Changes the validation state to blank state, this only applies
for mandatory widgets, draw an icon and set a tooltip"""
log.debug('Setting state for %s to BLANK' % self.model_attribute)
if self.mandatory:
self._draw_stock_icon(MANDATORY_ICON)
self.set_tooltip(_('This field is mandatory'))
self._fade.stop()
valid = False
else:
valid = True
self._set_valid_state(valid)
# Private
def _set_valid_state(self, state):
"""Updates the validation state and emits a signal iff it changed"""
if self._valid == state:
return
self.emit('validation-changed', state)
self._valid = state
def _draw_stock_icon(self, stock_id):
icon = self.render_icon(stock_id, gtk.ICON_SIZE_MENU)
self.set_pixbuf(icon)
self.queue_draw()
# Callbacks
def _on_fadeout__color_changed(self, fadeout, color):
self.update_background(color)
|