This commit is contained in:
Cédric Krier committed 2011-02-17 14:49:44 +01:00
commit 365b845a3e
18 files changed
+452 -64

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
* Added additional gtk.Entry for filename on BinaryField
* Display deleted lines in One2Many and Many2Many
* Handle URL
* Add communication between boards
* Added domain inversion feature
+230
View File
@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="90.000000"
inkscape:export-xdpi="90.000000"
inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
width="48px"
height="48px"
id="svg11300"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/actions"
sodipodi:docname="edit-undo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs3">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 24 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="48 : 24 : 1"
inkscape:persp3d-origin="24 : 16 : 1"
id="perspective31" />
<linearGradient
inkscape:collect="always"
id="linearGradient2326">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2328" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2330" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2316">
<stop
style="stop-color:#c4a000;stop-opacity:1;"
offset="0"
id="stop2318" />
<stop
style="stop-color:#c4a000;stop-opacity:0;"
offset="1"
id="stop2320" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2308">
<stop
style="stop-color:#edd400;stop-opacity:1;"
offset="0"
id="stop2310" />
<stop
style="stop-color:#edd400;stop-opacity:0;"
offset="1"
id="stop2312" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient8662">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop8664" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop8666" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient8662"
id="radialGradient8668"
cx="24.837126"
cy="36.421127"
fx="24.837126"
fy="36.421127"
r="15.644737"
gradientTransform="matrix(1.000000,0.000000,0.000000,0.536723,-6.227265e-14,16.87306)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient2187"
inkscape:collect="always">
<stop
id="stop2189"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop2191"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2187"
id="linearGradient1764"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.813471e-16,-1.171926,-1.171926,1.813471e-16,46.17440,54.10111)"
x1="17.060806"
y1="11.39502"
x2="12.624337"
y2="12.583769" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2308"
id="linearGradient2314"
x1="26.5"
y1="34.25"
x2="26.25"
y2="43.571831"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2316"
id="linearGradient2322"
x1="26.5"
y1="34.25"
x2="26.25"
y2="43.571831"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2326"
id="radialGradient2332"
cx="15.09403"
cy="13.282721"
fx="15.09403"
fy="13.282721"
r="10.16466"
gradientTransform="matrix(2.496031,-1.151905e-16,1.061756e-16,2.300689,-25.12402,-17.82636)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
stroke="#c4a000"
fill="#edd400"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="0.25490196"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="-19.855325"
inkscape:cy="-15.183692"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:showpageshadow="false"
inkscape:window-width="891"
inkscape:window-height="818"
inkscape:window-x="0"
inkscape:window-y="30" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:creator>
<dc:source>http://jimmac.musichall.cz</dc:source>
<cc:license
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
<dc:title>Edit Undo</dc:title>
<dc:subject>
<rdf:Bag>
<rdf:li>edit</rdf:li>
<rdf:li>undo</rdf:li>
<rdf:li>revert</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
transform="matrix(-1.489736,0.000000,0.000000,-1.001252,60.60436,75.31260)"
d="M 40.481863 36.421127 A 15.644737 8.3968935 0 1 1 9.1923885,36.421127 A 15.644737 8.3968935 0 1 1 40.481863 36.421127 z"
sodipodi:ry="8.3968935"
sodipodi:rx="15.644737"
sodipodi:cy="36.421127"
sodipodi:cx="24.837126"
id="path8660"
style="opacity:0.14117647;color:#000000;fill:url(#radialGradient8668);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
style="opacity:1;color:#000000;fill:url(#linearGradient2314);fill-opacity:1.0;fill-rule:nonzero;stroke:url(#linearGradient2322);stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
d="M 9.582441,45.034369 C 49.608249,46.355509 43.282405,12.29355 22.462411,12.49765 L 22.462411,3.1222396 L 5.8139298,17.708819 L 22.462411,33.006349 C 22.462411,33.006349 22.462411,23.337969 22.462411,23.337969 C 36.525521,22.751999 40.639939,44.770549 9.582441,45.034369 z "
id="path1432"
sodipodi:nodetypes="ccccccc" />
<path
sodipodi:nodetypes="ccccccc"
id="path2177"
d="M 31.032281,39.315519 C 42.75538,33.235892 39.220073,13.087489 21.448701,13.549959 L 21.448701,5.4508678 C 21.448701,5.4508678 7.4009628,17.714589 7.4009628,17.714589 L 21.448701,30.658617 C 21.448701,30.658617 21.448701,22.380979 21.448701,22.380979 C 36.288551,22.032709 35.608611,35.138579 31.032281,39.315519 z "
style="opacity:0.69886361;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient1764);stroke-width:0.9999997;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible" />
<path
style="opacity:0.51136364;color:#000000;fill:url(#radialGradient2332);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
d="M 6.6291261,17.682797 L 12.28598,23.074486 C 18.561553,22.897709 15.733126,16.710525 26.958446,13.616933 L 22.008699,12.998214 L 21.92031,4.3361562 L 6.6291261,17.682797 z "
id="path2324"
sodipodi:nodetypes="cccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

+7
View File
@@ -29,6 +29,8 @@ class CellRendererCombo(gtk.GenericCellRenderer):
gobject.PARAM_READWRITE),
'text-column': (gobject.TYPE_INT, 'Text Column',
'Text Column', 0, 10, 0, gobject.PARAM_READWRITE),
'strikethrough': (gobject.TYPE_BOOLEAN, 'Strikethrough',
'Strikethrough', False, gobject.PARAM_WRITABLE),
}
def __init__(self):
@@ -40,6 +42,11 @@ class CellRendererCombo(gtk.GenericCellRenderer):
self.editable = self._renderer.get_property('editable')
self.visible = True
def set_sensitive(self, value):
if hasattr(self._renderer, 'set_sensitive'):
return self._renderer.set_sensitive(value)
return self._renderer.set_property('sensitive', value)
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
+7
View File
@@ -22,6 +22,8 @@ class CellRendererDate(gtk.GenericCellRenderer):
'Editable', 0, 10, 0, gobject.PARAM_READWRITE),
'visible': (gobject.TYPE_INT, 'Visible',
'Visible', 0, 10, 0, gobject.PARAM_READWRITE),
'strikethrough': (gobject.TYPE_BOOLEAN, 'Strikethrough',
'Strikethrough', False, gobject.PARAM_WRITABLE),
}
def __init__(self, format):
@@ -36,6 +38,11 @@ class CellRendererDate(gtk.GenericCellRenderer):
self.editable = self._renderer.get_property('editable')
self.visible = True
def set_sensitive(self, value):
if hasattr(self._renderer, 'set_sensitive'):
return self._renderer.set_sensitive(value)
return self._renderer.set_property('sensitive', value)
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
+7
View File
@@ -23,6 +23,8 @@ class CellRendererText(gtk.GenericCellRenderer):
'XAlign', 0, 1, 0, gobject.PARAM_READWRITE),
'visible': (gobject.TYPE_INT, 'Visible',
'Visible', 0, 10, 0, gobject.PARAM_READWRITE),
'strikethrough': (gobject.TYPE_BOOLEAN, 'Strikethrough',
'Strikethrough', False, gobject.PARAM_WRITABLE),
}
def __init__(self):
@@ -34,6 +36,11 @@ class CellRendererText(gtk.GenericCellRenderer):
self.editable = self._renderer.get_property('editable')
self.visible = True
def set_sensitive(self, value):
if hasattr(self._renderer, 'set_sensitive'):
return self._renderer.set_sensitive(value)
return self._renderer.set_property('sensitive', value)
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
+5
View File
@@ -27,6 +27,11 @@ class CellRendererToggle(gtk.GenericCellRenderer):
self.activatable = self._renderer.get_property('activatable')
self.visible = True
def set_sensitive(self, value):
if hasattr(self._renderer, 'set_sensitive'):
return self._renderer.set_sensitive(value)
return self._renderer.set_property('sensitive', value)
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
if pspec.name == 'visible':
+18 -13
View File
@@ -24,17 +24,22 @@ class Shortcuts(object):
self.dialog.vbox.pack_start(notebook)
shortcuts = [
(_('Text Entries Shortcuts'),),
('<Ctrl> + X', _('Cut selected text')),
('<Ctrl> + C', _('Copy selected text')),
('<Ctrl> + V', _('Paste copied text')),
('<Tab>', _('Next widget')),
('<Shift> + <Tab>', _('Previous widget')),
(_('Relation Entries Shortcuts'),),
('<F3>', _('Create new relation')),
('<F2>', _('Open/Search relation')),
(_('Date/Datetime Entries Shortcuts'),),
(_('''You can use special operators:
(_('Text Entries Shortcuts'),),
('<Ctrl> + X', _('Cut selected text')),
('<Ctrl> + C', _('Copy selected text')),
('<Ctrl> + V', _('Paste copied text')),
('<Tab>', _('Next widget')),
('<Shift> + <Tab>', _('Previous widget')),
(_('Relation Entries Shortcuts'),),
('<F3>', _('Create new relation')),
('<F2>', _('Open/Search relation')),
(_('List Entries Shortcuts'),),
('<F3>', _('Create new line')),
('<F2>', _('Open relation')),
('<Del>', _('Mark line for deletion')),
('<Ins>', _('Unmark line for deletion')),
(_('Date/Datetime Entries Shortcuts'),),
(_('''You can use special operators:
* + to increase the date
* - to decrease the date or clear
* = to set the date or the current date
@@ -49,8 +54,8 @@ y for years
Examples:
"+21d" increase of 21 days the date
"=11m" set the date to the 11th month of the year
"-2w" decrease of 2 weeks the date'''),)
]
"-2w" decrease of 2 weeks the date'''),),
]
notebook.append_page(self._fill_table(shortcuts),
gtk.Label(_('Edition Widgets')))
+9 -5
View File
@@ -179,7 +179,7 @@ class CharField(object):
def get_state_attrs(self, record):
if self.name not in record.state_attrs:
record.state_attrs[self.name] = self.attrs.copy()
if record.group.readonly:
if record.group.readonly or record.readonly:
record.state_attrs[self.name]['readonly'] = True
return record.state_attrs[self.name]
@@ -449,10 +449,10 @@ class O2MField(CharField):
record2.get(check_load=check_load, get_readonly=readonly)))
if record.value[self.name].record_removed:
result.append(('unlink', [x.id for x in \
record.value[self.name].record_removed]))
record.value[self.name].record_removed]))
if record.value[self.name].record_deleted:
result.append(('delete', [x.id for x in \
record.value[self.name].record_deleted]))
record.value[self.name].record_deleted]))
return result
def get_timestamp(self, record):
@@ -473,7 +473,8 @@ class O2MField(CharField):
if record.value.get(self.name) is None:
return []
for record2 in record.value[self.name]:
result.append(record2.get_eval(check_load=check_load))
if not (record2.deleted or record2.removed):
result.append(record2.get_eval(check_load=check_load))
return result
def set(self, record, value, modified=False):
@@ -531,7 +532,7 @@ class O2MField(CharField):
parent_datetime_field=self.attrs.get('datetime_field'))
if record.value.get(self.name):
group.record_deleted.extend(x for x in record.value[self.name]
if x.id > 0)
if x.id > 0)
group.record_deleted.extend(record.value[self.name].record_deleted)
group.record_removed.extend(record.value[self.name].record_removed)
record.value[self.name] = group
@@ -698,6 +699,9 @@ class ReferenceField(CharField):
if not value:
record.value[self.name] = False
return
if isinstance(value, basestring):
model, ref_id = value.split(',')
value = model, (ref_id, record.value.get(self.name + '.rec_name'))
ref_model, (ref_id, ref_str) = value
if ref_model:
ref_id = int(ref_id)
+26 -15
View File
@@ -27,8 +27,7 @@ class Group(SignalEvent, list):
self.load_fields(fields)
self.current_idx = None
self.load(ids)
self.record_removed = []
self.record_deleted = []
self.record_deleted, self.record_removed = [], []
self.on_write = set()
self.readonly = readonly
if self._context.get('_datetime'):
@@ -87,8 +86,7 @@ class Group(SignalEvent, list):
if not self.lock_signal:
self.signal('group-list-changed', ('group-cleared',))
self.__id2record = {}
self.record_removed = []
self.record_deleted = []
self.record_removed, self.record_deleted = [], []
def move(self, record, pos):
self.lock_signal = True
@@ -159,9 +157,16 @@ class Group(SignalEvent, list):
def load(self, ids, display=True, modified=False):
if not ids:
return True
# Work with sets to compute intersection and set difference
set_records = set(self.get(x) for x in ids)
for record in set_records & set(self.record_removed):
self.record_removed.remove(record)
for record in set_records & set(self.record_deleted):
self.record_deleted.remove(record)
old_ids = [x.id for x in self]
ids = [x for x in ids if x not in old_ids]
set_records -= set(x for x in self)
# return on the list form in order to preserver ordering
ids = [x for x in ids if self.get(x) in set_records]
if not ids:
return True
@@ -177,12 +182,6 @@ class Group(SignalEvent, list):
self._record_changed)
new_record.signal_connect(self, 'record-modified',
self._record_modified)
for record in self.record_removed[:]:
if record.id in ids:
self.record_removed.remove(record)
for record in self.record_deleted[:]:
if record.id in ids:
self.record_deleted.remove(record)
if self.lock_signal:
self.lock_signal = False
self.signal('group-cleared')
@@ -253,18 +252,31 @@ class Group(SignalEvent, list):
self.signal('group-changed', record)
return record
def unremove(self, record, signal=True):
if record in self.record_removed:
self.record_removed.remove(record)
if record in self.record_deleted:
self.record_deleted.remove(record)
if signal:
record.signal('record-changed', record.parent)
def remove(self, record, remove=False, modified=True, signal=True):
idx = self.index(record)
if self[idx].id > 0:
if remove:
if self[idx] in self.record_deleted:
self.record_deleted.remove(self[idx])
self.record_removed.append(self[idx])
else:
if self[idx] in self.record_removed:
self.record_removed.remove(self[idx])
self.record_deleted.append(self[idx])
if record.parent:
record.parent.modified = True
if modified:
record.modified = True
self._remove(self[idx])
if not record.parent or self[idx].id <= 0:
self._remove(self[idx])
if len(self):
self.current_idx = min(idx, len(self) - 1)
@@ -351,8 +363,7 @@ class Group(SignalEvent, list):
for field in self.fields.itervalues():
field.destroy()
self.fields = {}
self.record_removed = None
self.record_deleted = None
self.record_deleted, self.record_removed = [], []
self.__id2record = None
for record in self:
record.destroy()
@@ -106,6 +106,25 @@ class Record(SignalEvent):
modified = property(get_modified, set_modified)
def get_removed(self):
if self.group is not None:
return self in self.group.record_removed
return False
removed = property(get_removed)
def get_deleted(self):
if self.group is not None:
return self in self.group.record_deleted
return False
deleted = property(get_deleted)
def get_readonly(self):
return self.deleted or self.removed
readonly = property(get_readonly)
def is_modified(self):
return self.modified
@@ -504,6 +504,10 @@ class Screen(SignalEvent):
self.display()
self.request_set()
def unremove(self):
if self.current_record in self.group:
self.group.unremove(self.current_record)
def remove(self, delete=False, remove=False):
res = False
reload_ids = []
@@ -9,6 +9,12 @@ from interface import WidgetInterface
_ = gettext.gettext
def humanize(size):
for x in ('bytes', 'KB', 'MB', 'GB', 'TB', 'PB'):
if size < 1000:
return '%3.1f%s' % (size, x)
size /= 1000.0
class Binary(WidgetInterface):
"Binary"
@@ -17,12 +23,26 @@ class Binary(WidgetInterface):
super(Binary, self).__init__(field_name, model_name, window,
attrs=attrs)
self.filename = attrs.get('filename')
self.filename_visible = attrs.get('filename_visible')
self.tooltips = Tooltips()
self.widget = gtk.HBox(spacing=0)
self.wid_text = gtk.Entry()
self.wid_text.set_property('activates_default', True)
self.widget.pack_start(self.wid_text, expand=True, fill=True)
if self.filename and self.filename_visible:
self.wid_text = gtk.Entry()
self.wid_text.set_property('activates_default', True)
self.wid_text.connect('focus-in-event', lambda x, y: self._focus_in())
self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out())
self.wid_text.connect_after('key_press_event', self.sig_key_press)
self.wid_size = gtk.Entry()
self.wid_size.set_width_chars(11)
self.wid_size.props.sensitive = False
self.widget.pack_start(self.wid_text, expand=True, fill=True)
else:
self.wid_text = None
self.widget.pack_start(self.wid_size, expand=not self.filename,
fill=True)
self.but_new = gtk.Button()
img_new = gtk.Image()
@@ -35,7 +55,8 @@ class Binary(WidgetInterface):
self.but_save_as = gtk.Button()
img_save_as = gtk.Image()
img_save_as.set_from_stock('tryton-save-as', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_save_as.set_from_stock('tryton-save-as',
gtk.ICON_SIZE_SMALL_TOOLBAR)
self.but_save_as.set_image(img_save_as)
self.but_save_as.set_relief(gtk.RELIEF_NONE)
self.but_save_as.connect('clicked', self.sig_save_as)
@@ -61,11 +82,17 @@ class Binary(WidgetInterface):
else:
self.but_new.show()
self.but_remove.show()
self.widget.set_focus_chain([self.but_new, self.but_save_as,
self.but_remove])
if self.wid_text:
focus_chain = [self.wid_text]
else:
focus_chain = [self.but_new, self.but_save_as, self.but_remove]
self.widget.set_focus_chain(focus_chain)
def grab_focus(self):
return self.wid_text.grab_focus()
if self.wid_text:
return self.wid_text.grab_focus()
else:
return self.wid_size.grab_focus()
def sig_new(self, widget=None):
try:
@@ -74,9 +101,9 @@ class Binary(WidgetInterface):
if filename and self.field:
self.field.set_client(self.record,
base64.encodestring(open(filename, 'rb').read()))
fname = self.attrs.get('fname_widget', False)
if fname:
self.parent.value = {fname:os.path.basename(filename)}
if self.filename and self.filename_visible and self.record:
name_wid = self.record.group.fields[self.filename]
name_wid.set_client(self.record, os.path.basename(filename))
self.display(self.record, self.field)
except Exception, exception:
warning(_('Error reading the file.\nError message:\n%s') \
@@ -98,29 +125,47 @@ class Binary(WidgetInterface):
def sig_remove(self, widget=None):
if self.field:
self.field.set_client(self.record, False)
fname = self.attrs.get('fname_widget', False)
if fname:
self.parent.value = {fname:False}
self.display(self.record, self.field)
def sig_key_press(self, widget, event, *args):
editable = self.wid_text and self.wid_text.get_editable()
if event.keyval == gtk.keysyms.F3 and editable:
self.sig_new(widget)
return True
elif event.keyval == gtk.keysyms.F2:
self.sig_save_as(widget)
return True
return False
def display(self, record, field):
super(Binary, self).display(record, field)
if not field:
self.wid_text.set_text('')
if self.wid_text:
self.wid_text.set_text('')
self.wid_size.set_text('')
self.but_save_as.set_sensitive(False)
return False
self.wid_text.set_text(self._size_get(field.get(record)))
if self.wid_text:
name_wid = record.group.fields[self.filename]
self.wid_text.set_text(name_wid.get(record) or '')
self.wid_size.set_text(humanize(len(field.get(record) or [])))
self.but_save_as.set_sensitive(bool(field.get(record)))
return True
def display_value(self):
return self.wid_text.get_text()
def _size_get(self, value):
return value and ('%d ' + _('bytes')) % len(value) or ''
if self.wid_text:
return self.wid_text.get_text()
else:
return ''
def set_value(self, record, field):
if self.wid_text:
name_wid = self.record.group.fields[self.filename]
name_wid.set_client(self.record, self.wid_text.get_text() or False)
return
def _color_widget(self):
return self.wid_text
if self.wid_text:
return self.wid_text
else:
return self.wid_size
@@ -20,6 +20,7 @@ class Image(WidgetInterface):
super(Image, self).__init__(field_name, model_name, window,
attrs=attrs)
self.filename = attrs.get('filename')
self.height = int(attrs.get('img_height', 100))
self.width = int(attrs.get('img_width', 300))
@@ -102,6 +103,9 @@ class Image(WidgetInterface):
if filename:
self.field.set_client(self.record,
encodestring(open(filename, 'rb').read()))
if self.filename and self.record:
name_wid = self.record.group.fields[self.filename]
name_wid.set_client(self.record, os.path.basename(filename))
self.update_img()
def sig_save_as(self, widget):
@@ -167,6 +167,7 @@ class WidgetInterface(object):
'fg_color_normal': style.fg[gtk.STATE_NORMAL],
'fg_color_insensitive': style.fg[gtk.STATE_INSENSITIVE],
'text_color_normal': style.text[gtk.STATE_NORMAL],
'text_color_insensitive': style.text[gtk.STATE_INSENSITIVE],
}
if COLORS.get(name):
@@ -96,6 +96,15 @@ class Many2Many(WidgetInterface):
self.widget.destroy()
del self.widget
def color_set(self, name):
super(Many2Many, self).color_set(name)
widget = self._color_widget()
# if the style to apply is different from readonly then insensitive
# cellrenderers should use the default insensitive color
if name != 'readonly':
widget.modify_text(gtk.STATE_INSENSITIVE,
self.colors['text_color_insensitive'])
def _sig_add(self, *args):
domain = self.field.domain_get(self.record)
context = self.field.context_get(self.record)
@@ -104,7 +104,7 @@ class One2Many(WidgetInterface):
self.but_del = gtk.Button()
tooltips.set_tip(self.but_del, _('Delete selected record'))
self.but_del.connect('clicked', self._sig_remove)
self.but_del.connect('clicked', self._sig_remove, False)
img_del = gtk.Image()
img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_del.set_alignment(0.5, 0.5)
@@ -112,6 +112,16 @@ class One2Many(WidgetInterface):
self.but_del.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_del, expand=False, fill=False)
self.but_undel = gtk.Button()
tooltips.set_tip(self.but_undel, _('Undelete selected record'))
self.but_undel.connect('clicked', self._sig_undelete)
img_undel = gtk.Image()
img_undel.set_from_stock('tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)
img_undel.set_alignment(0.5, 0.5)
self.but_undel.add(img_undel)
self.but_undel.set_relief(gtk.RELIEF_NONE)
hbox.pack_start(self.but_undel, expand=False, fill=False)
hbox.pack_start(gtk.VSeparator(), expand=False, fill=True)
self.but_pre = gtk.Button()
@@ -195,6 +205,9 @@ class One2Many(WidgetInterface):
and widget == self.screen.widget:
self._sig_remove(widget)
return False
if event.keyval == gtk.keysyms.Insert and widget == self.screen.widget:
self._sig_undelete(widget)
return False
def destroy(self):
self.screen.destroy()
@@ -206,6 +219,15 @@ class One2Many(WidgetInterface):
self.screen.switch_view()
self.color_set(self.color_name)
def color_set(self, name):
super(One2Many, self).color_set(name)
widget = self._color_widget()
# if the style to apply is different from readonly then insensitive
# cellrenderers should use the default insensitive color
if name != 'readonly':
widget.modify_text(gtk.STATE_INSENSITIVE,
self.colors['text_color_insensitive'])
def _readonly_set(self, value):
self._readonly = value
self.but_new.set_sensitive(not value)
@@ -231,12 +253,6 @@ class One2Many(WidgetInterface):
self.screen.new(context=ctx)
self.screen.current_view.widget.set_sensitive(True)
else:
readonly = False
domain = []
if self.field and self.record:
readonly = self.field.get_state_attrs(self.record
).get('readonly', False)
domain = self.field.domain_get(self.record)
win = WinForm(self.screen, self.window, new=True,
context=ctx)
while True:
@@ -250,8 +266,9 @@ class One2Many(WidgetInterface):
def _sig_edit(self, widget=None):
self.view.set_value()
if self.screen.current_record:
if not self.screen.current_record.validate():
record = self.screen.current_record
if record:
if not record.validate():
self.screen.display()
return
win = WinForm(self.screen, self.window)
@@ -277,6 +294,9 @@ class One2Many(WidgetInterface):
def _sig_remove(self, widget, remove=False):
self.screen.remove(remove=remove)
def _sig_undelete(self, button):
self.screen.unremove()
def _sig_activate(self, *args):
self._sig_add()
self.wid_text.grab_focus()
@@ -333,9 +353,12 @@ class One2Many(WidgetInterface):
self.but_pre.set_sensitive(True)
else:
self.but_pre.set_sensitive(False)
self.but_del.set_sensitive(True)
self.but_undel.set_sensitive(True)
else:
self.but_open.set_sensitive(False)
self.but_del.set_sensitive(False)
self.but_undel.set_sensitive(False)
self.but_next.set_sensitive(False)
self.but_pre.set_sensitive(False)
if self.attrs.get('add_remove'):
@@ -518,7 +518,7 @@ class ParserForm(ParserInterface):
continue
for attr_name in ('relation', 'domain', 'selection',
'relation_field', 'string', 'views', 'invisible',
'add_remove', 'sort', 'context', 'size'):
'add_remove', 'sort', 'context', 'size', 'filename'):
if attr_name in fields[name].attrs and \
not attr_name in attrs:
attrs[attr_name] = fields[name].attrs[attr_name]
@@ -250,6 +250,10 @@ class Char(object):
if isinstance(cell, CellRendererToggle):
cell.set_active(bool(text))
else:
cell.set_sensitive(not (record.deleted or record.removed))
if isinstance(cell,
(CellRendererText, CellRendererDate, CellRendererCombo)):
cell.set_property('strikethrough', record.deleted)
cell.set_property('text', text)
fg_color = self.get_color(record)
cell.set_property('foreground', fg_color)
@@ -293,7 +297,8 @@ class Char(object):
cell.set_property('background-set', False)
else:
cell.set_property('background-set', True)
cell.set_property('foreground-set', True)
cell.set_property('foreground-set',
not (record.deleted or record.removed))
if isinstance(cell, CellRendererToggle):
cell.set_property('activatable', not readonly)