Naresh(OpenERP) has proposed merging
lp:~nch-openerp/openobject-client/nch_dynamic_searchview into
lp:openobject-client.
Requested reviews:
OpenERP sa GTK client R&D (openerp-dev-gtk)
For more details, see:
https://code.launchpad.net/~nch-openerp/openobject-client/nch_dynamic_searchview/+merge/50897
Hello,
This branch contains the improved Custom filter. You can now get more user
friendly widgets while creating a custom filter. like say if you select a field
in custom filter of type Many2one then you criteria input widget will be
changed to a many2one widgets where you can select any records you want.
Similarly if the field selected is a selection type then you get a drop down
selection widgets with the fields filled in. you just need to select the value.
the domain will be created based on key but the user can now select the value.
Similarly for other widgets too.
Thanks,
--
https://code.launchpad.net/~nch-openerp/openobject-client/nch_dynamic_searchview/+merge/50897
Your team OpenERP sa GTK client R&D is requested to review the proposed merge
of lp:~nch-openerp/openobject-client/nch_dynamic_searchview into
lp:openobject-client.
=== modified file 'bin/openerp.glade'
--- bin/openerp.glade 2011-01-17 14:10:46 +0000
+++ bin/openerp.glade 2011-02-23 10:37:57 +0000
@@ -8242,83 +8242,6 @@
</widget>
</child>
</widget>
- <widget class="GtkHBox" id="hbox_custom_filter">
- <property name="visible">True</property>
- <property name="spacing">5</property>
- <child>
- <widget class="GtkComboBox" id="combo_fields">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Fields on which Search criteria to be applied</property>
- <property name="items" translatable="yes"></property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkComboBox" id="combo_operator">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Conditional Operators</property>
- <property name="items" translatable="yes"></property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="right_compare">
- <property name="visible">True</property>
- <property name="editable">True</property>
- <property name="can_focus">True</property>
- <property name="activates_default">True</property>
- <property name="width_chars">21</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <widget class="GtkComboBox" id="cond_custom">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">The Choice will be applied with next filter if any</property>
- <property name="items" translatable="yes">AND
-OR</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <widget class="GtkButton" id="remove_custom">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Remove Filter</property>
- <signal name="button_press_event" handler="on_remove_custom"/>
- <child>
- <widget class="GtkImage" id="image4168">
- <property name="visible">True</property>
- <property name="stock">gtk-remove</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">5</property>
- </packing>
- </child>
- </widget>
<widget class="GtkDialog" id="dia_get_action">
<property name="width_request">230</property>
<property name="height_request">122</property>
=== modified file 'bin/widget/screen/screen.py'
--- bin/widget/screen/screen.py 2011-01-27 12:43:03 +0000
+++ bin/widget/screen/screen.py 2011-02-23 10:37:57 +0000
@@ -113,7 +113,6 @@
self.old_limit = limit
self.offset = 0
self.readonly= readonly
- self.custom_panels = []
self.view_fields = {} # Used to switch self.fields when the view switchs
self.sort_domain = []
self.old_ctx = {}
@@ -157,11 +156,7 @@
self.filter_widget = widget_search.form(self.search_view['arch'],
self.search_view['fields'], self.name, self.window,
self.domain, (self, self.search_filter))
- self.screen_container.add_filter(self.filter_widget.widget,
- self.search_filter, self.search_clear,
- self.search_offset_next,
- self.search_offset_previous,
- self.execute_action, self.add_custom, self.name, self.limit)
+ self.screen_container.add_filter(self)
if active and show_search:
self.screen_container.show_filter()
@@ -285,21 +280,6 @@
self.load(ids)
return True
- def add_custom(self, dynamic_button):
- fields_list = []
- for k,v in self.search_view['fields'].items():
- if v['type'] in ('many2one','text','char','float','integer','date','datetime','selection','many2many','boolean','one2many') and v.get('selectable', False):
- selection = v.get('selection', False)
- fields_list.append([k,v['string'], v['type'], selection])
- if fields_list:
- fields_list.sort(lambda x, y: cmp(x[1], y[1]))
- panel = self.filter_widget.add_custom(self.filter_widget, self.filter_widget.widget, fields_list)
- self.custom_panels.append(panel)
-
- if len(self.custom_panels)>1:
- self.custom_panels[-1].condition_next.hide()
- self.custom_panels[-2].condition_next.show()
-
def execute_action(self, combo):
flag = combo.get_active_text()
combo_model = combo.get_model()
=== modified file 'bin/widget/view/screen_container.py'
--- bin/widget/view/screen_container.py 2011-01-10 11:59:36 +0000
+++ bin/widget/view/screen_container.py 2011-02-23 10:37:57 +0000
@@ -26,7 +26,6 @@
from rpc import RPCProxy
import rpc
-
class screen_container(object):
def __init__(self, win_search=False):
self.old_widget = False
@@ -48,6 +47,7 @@
self.domain = []
self.context = {}
self.handler_id = None
+ self.custom_panels = []
def __del__(self):
for (ref, value) in self.__dict__.items():
@@ -100,7 +100,15 @@
self.action_list.foreach(fnct, filter_name)
return str(self.domain),str(self.context)
- def add_filter(self, widget, fnct, clear_fnct, next_fnct, prev_fnct, execute_action=None, add_custom=None, model=None, limit=100):
+ def add_custom_filter(self, button, screen):
+ fields = screen.search_view.get('fields', {})
+ panel = screen.filter_widget.add_custom(screen.filter_widget, screen.filter_widget.widget, fields)
+ self.custom_panels.append(panel)
+ if len(self.custom_panels)>1:
+ self.custom_panels[-1].condition_next.hide()
+ self.custom_panels[-2].condition_next.show()
+
+ def add_filter(self, screen):
self.filter_vbox = gtk.VBox(spacing=1)
self.filter_vbox.set_border_width(1)
if self.help and not self.win_search:
@@ -108,14 +116,14 @@
self.help_frame = action_tips.help_frame
if self.help_frame:
self.filter_vbox.pack_start(self.help_frame, expand=False, fill=False, padding=3)
- self.filter_vbox.pack_start(widget, expand=True, fill=True)
+ self.filter_vbox.pack_start(screen.filter_widget.widget, expand=True, fill=True)
hs = gtk.HBox(homogeneous=False, spacing=0)
hb1 = gtk.HButtonBox()
hb1.set_layout(gtk.BUTTONBOX_START)
button_clear = gtk.Button(stock=gtk.STOCK_CLEAR)
- button_clear.connect('clicked', clear_fnct)
+ button_clear.connect('clicked', screen.search_clear)
if self.win_search:
hb3 = hb1
hs.pack_start(hb3, expand=False, fill=False)
@@ -130,7 +138,7 @@
#Find Clear Buttons
self.button = gtk.Button(stock=gtk.STOCK_FIND)
- self.button.connect('clicked', fnct)
+ self.button.connect('clicked', screen.search_filter)
self.button.set_property('can_default', True)
hb1.pack_start(self.button, expand=False, fill=False)
hb1.pack_start(button_clear, expand=False, fill=False)
@@ -143,9 +151,9 @@
self.action_combo.pack_start(cell, True)
self.action_combo.add_attribute(cell, 'text', 2)
- self.fill_filter_combo(model)
+ self.fill_filter_combo(screen.name)
self.action_combo.set_active(0)
- self.handler_id = self.action_combo.connect('changed', execute_action)
+ self.handler_id = self.action_combo.connect('changed', screen.execute_action)
#Custom Filter Button
img2 = gtk.Image()
@@ -154,7 +162,7 @@
self.button_dynamic.set_image(img2)
self.button_dynamic.set_relief(gtk.RELIEF_NONE)
self.button_dynamic.set_alignment(0.3,0.3)
- self.button_dynamic.connect('clicked', add_custom)
+ self.button_dynamic.connect('clicked', self.add_custom_filter, screen)
hb2.pack_start(gtk.Label(''), expand=True, fill=True)
hb2.pack_start(self.action_combo, expand=False, fill=False)
@@ -170,7 +178,7 @@
self.selection = []
hb3.pack_start(self.combo, expand=False, fill=False)
- self.fill_limit_combo(limit)
+ self.fill_limit_combo(screen.limit)
#Back Forward Buttons
@@ -179,14 +187,14 @@
icon.set_from_stock('gtk-go-back', gtk.ICON_SIZE_SMALL_TOOLBAR)
self.but_previous.set_image(icon)
self.but_previous.set_relief(gtk.RELIEF_NONE)
- self.but_previous.connect('clicked', prev_fnct)
+ self.but_previous.connect('clicked', screen.search_offset_previous)
icon2 = gtk.Image()
icon2.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_SMALL_TOOLBAR)
self.but_next = gtk.Button()
self.but_next.set_image(icon2)
self.but_next.set_relief(gtk.RELIEF_NONE)
- self.but_next.connect('clicked', next_fnct)
+ self.but_next.connect('clicked', screen.search_offset_next)
next_prev_box = hb3
if self.win_search:
next_prev_box = gtk.HBox(homogeneous=False, spacing=0)
=== modified file 'bin/widget_search/calendar.py'
--- bin/widget_search/calendar.py 2011-01-06 09:49:16 +0000
+++ bin/widget_search/calendar.py 2011-02-23 10:37:57 +0000
@@ -58,8 +58,8 @@
img.set_alignment(0.5, 0.5)
self.eb1.add(img)
self.widget.pack_start(self.eb1, expand=False, fill=False)
-
- self.widget.pack_start(gtk.Label('-'), expand=False, fill=False)
+ self.label = gtk.Label('-')
+ self.widget.pack_start(self.label, expand=False, fill=False)
self.widget2 = date_widget.ComplexEntry(self.format, spacing=3)
self.entry2 = self.widget2.widget
@@ -186,8 +186,8 @@
img.set_alignment(0.5, 0.5)
self.eb1.add(img)
self.widget.pack_start(self.eb1, expand=False, fill=False)
-
- self.widget.pack_start(gtk.Label('-'), expand=False, fill=False)
+ self.label = gtk.Label('-')
+ self.widget.pack_start(self.label, expand=False, fill=False)
self.widget2 = date_widget.ComplexEntry(self.format, spacing=3)
self.entry2 = self.widget2.widget
=== modified file 'bin/widget_search/custom_filter.py'
--- bin/widget_search/custom_filter.py 2011-01-25 10:58:55 +0000
+++ bin/widget_search/custom_filter.py 2011-02-23 10:37:57 +0000
@@ -19,143 +19,90 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-
import gtk
-from datetime import datetime
-import gettext
-from gtk import glade
-
-import tools
import wid_int
-import common
+import custom_filter_widgets
-DT_FORMAT = '%Y-%m-%d'
-DHM_FORMAT = '%Y-%m-%d %H:%M:%S'
class custom_filter(wid_int.wid_int):
- def __init__(self, name, parent, attrs={}, call=None):
- wid_int.wid_int.__init__(self, name, parent, attrs)
- win_gl = glade.XML(common.terp_path("openerp.glade"),"hbox_custom_filter",gettext.textdomain())
- self.widget = win_gl.get_widget('hbox_custom_filter')
-
- # Processing fields
- self.combo_fields = win_gl.get_widget('combo_fields')
+ def __init__(self, name, parent, fields={}, callback=None):
+ wid_int.wid_int.__init__(self, name, parent)
+
+ self.fields = fields
+
self.field_selection = {}
-
- fields = attrs.get('fields',None)
- for item in fields:
- self.field_selection[item[1]] = (item[0], item[2], item[3])
+ self.op_selection = {}
+
+ self.widget = gtk.HBox()
+ # fields_list combo
+ self.combo_fields = gtk.combo_box_new_text()
+ self.combo_fields.connect('changed', self.on_fields_combo_changed)
+
+ self.combo_op = gtk.combo_box_new_text()
+ self.combo_op.connect('changed', self.on_operator_combo_changed)
+
+ self.condition_next = gtk.combo_box_new_text()
+ self.condition_next.append_text(_('AND'))
+ self.condition_next.append_text(_('OR'))
+ self.condition_next.set_active(0)
+ self.condition_next.hide()
+
+ self.remove_filter = gtk.Button()
+ img = gtk.Image()
+ img.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON)
+ self.remove_filter.add(img)
+ self.remove_filter.set_relief(gtk.RELIEF_NONE)
+ self.remove_filter.connect('clicked', callback, self)
+
+ self.right_text = gtk.Entry()
+
+ self.widget.pack_start(self.combo_fields)
+ self.widget.pack_start(self.combo_op)
+ self.widget.pack_start(self.right_text)
+ self.widget.pack_start(self.condition_next)
+ self.widget.pack_start(self.remove_filter)
+ self.widget.show_all()
+ sorted_names = []
+ for key, attr in self.fields.iteritems():
+ sorted_names.append([key,attr['string'], attr['type']])
+ sorted_names.sort(lambda x, y:cmp(x[1], y[1]))
+ for item in sorted_names:
+ self.field_selection[item[1]] = (item[0], item[2])
self.combo_fields.append_text(item[1])
-
self.combo_fields.set_active(0)
- # Processing operator combo
- self.combo_op = win_gl.get_widget('combo_operator')
+ def on_operator_combo_changed(self, combo):
+ self.widget_obj.selected_oper_text = self.combo_op.get_active_text()
+ self.widget_obj.set_visibility()
+ return True
+
+ def on_fields_combo_changed(self, combo):
+ field_string = self.combo_fields.get_active_text()
+ field_dbname, type = self.field_selection[field_string]
+ if self.right_text:
+ self.widget.remove(self.right_text)
+ self.widget_obj = custom_filter_widgets.widgets_type[type](field_string, self.parent, self.fields.get(field_dbname, {}))
+ self.right_text = self.widget_obj.widget
self.op_selection = {}
-
- for item in (['ilike', _('contains')],
- ['not ilike', _('doesn\'t contain')],
- ['=', _('is equal to')],
- ['<>',_('is not equal to')],
- ['>',_('greater than')],
- ['<',_('less than')],
- ['in',_('in')],
- ['not in',_('not in')],
- ):
- self.op_selection[item[1]] = item[0]
- self.combo_op.append_text(item[1])
-
+ self.combo_op.get_model().clear()
+ for operator in self.widget_obj.operators:
+ self.op_selection[operator[1]] = operator[0]
+ self.combo_op.append_text(operator[1])
+ self.widget.pack_start(self.right_text)
+ self.widget.reorder_child(self.right_text, 2)
+ self.widget.show_all()
self.combo_op.set_active(0)
-
- # Processing text value
- self.right_text = win_gl.get_widget('right_compare')
- # Processing Custom conditions
- self.condition_next = win_gl.get_widget('cond_custom')
- self.condition_next.set_active(0)
-
self.condition_next.hide()
- # Processing Removal of panel
- self.remove_filter = win_gl.get_widget('remove_custom')
- self.remove_filter.set_relief(gtk.RELIEF_NONE)
-
- try:
- self.right_text.set_tooltip_markup(tools.to_xml(_("Enter Values separated by ',' if operator 'in' or 'not in' is chosen.\nFor Date and DateTime Formats, specify text in '%Y-%m-%d' and '%Y-%m-%d %H:%M:%S' formats respectively.")))
- except:
- pass
-
- self.remove_filter.connect('clicked',call,self)
+ return True
def _value_get(self):
- try:
- false_value_domain = []
- type_cast = {'integer':lambda x:int(x),
- 'float':lambda x:float(x),
- 'boolean':lambda x:bool(eval(x)),
- 'date':lambda x:(datetime.strptime(x, DT_FORMAT)).strftime(DT_FORMAT),
- 'datetime':lambda x:(datetime.strptime(x, DHM_FORMAT)).strftime(DHM_FORMAT)
- }
- field_left = self.field_selection[self.combo_fields.get_active_text()][0]
- field_type = self.field_selection[self.combo_fields.get_active_text()][1]
- operator = self.op_selection[self.combo_op.get_active_text()]
- right_text = self.right_text.get_text() or False
-
- if operator in ['not ilike','<>', 'not in'] and field_type != 'boolean':
- false_value_domain = ['|', (field_left,'=', False)]
- try:
- cast_type = True
- if field_type in type_cast:
- if field_type in ('date','datetime'):
- if right_text:
- if field_type == 'datetime':
- right_text = len(right_text)==10 and (right_text + ' 00:00:00') or right_text
- else:
- cast_type = False
- if cast_type:
- right_text = type_cast[field_type](right_text)
- self.right_text.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.color_parse("white"))
- self.right_text.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse("white"))
-
- except Exception,e:
- right_text = ''
- self.right_text.set_text('Invalid Value')
- self.right_text.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.color_parse("#ff6969"))
- self.right_text.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ff6969"))
- return {}
- if operator in ['ilike','not ilike']:
- if field_type in ['integer','float','date','datetime','boolean']:
- operator = (operator == 'ilike') and '=' or '!='
- else:
- right_text = '%' + right_text + '%'
-
- if operator in ['<','>'] and field_type not in ['integer','float','date','datetime','boolean']:
- operator = '='
-
- if operator in ['in','not in']:
- right_text = right_text.split(',')
-
- # Cannot use the active_text as it will be translated!
- # So as a workaround we use the index: 0 == AND, 1 == OR
- condition = self.condition_next.get_active() == 0 and '&' or '|'
-
- if field_type == 'selection' and right_text:
- right_text_se = self.right_text.get_text()
- keys = []
- for selection in self.field_selection[self.combo_fields.get_active_text()][2]:
- if selection[1].lower().find(right_text_se.lower()) != -1:
- keys.append(selection[0])
- right_text = keys
- if operator in ['ilike','=','in']:
- operator = 'in'
- else:
- operator = 'not in'
-
- domain = [condition, (field_left, operator, right_text)]
- if false_value_domain:
- domain = false_value_domain + domain
- return {'domain':domain}
-
- except Exception,e:
- return {}
+ self.widget_obj.field_left = self.field_selection[self.combo_fields.get_active_text()][0]
+ self.widget_obj.selected_oper_text = self.combo_op.get_active_text()
+ self.widget_obj.selected_oper = self.op_selection[self.widget_obj.selected_oper_text]
+ wid_domain = self.widget_obj._value_get()
+ condition = self.condition_next.get_active() == 0 and '&' or '|'
+ domain = [condition] + wid_domain
+ return {'domain':domain}
def sig_exec(self, widget):
pass
@@ -171,9 +118,12 @@
return True
def sig_activate(self, fct):
- self.right_text.connect_after('activate', fct)
+ try:
+ self.right_text.connect_after('activate', fct)
+ except:
+ pass
value = property(_value_get, _value_set, None,
_('The content of the widget or ValueError if not valid'))
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
=== added file 'bin/widget_search/custom_filter_widgets.py'
--- bin/widget_search/custom_filter_widgets.py 1970-01-01 00:00:00 +0000
+++ bin/widget_search/custom_filter_widgets.py 2011-02-23 10:37:57 +0000
@@ -0,0 +1,372 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+import gtk
+import wid_int
+import calendar
+from calendar import calendar,datetime
+from spinbutton import spinbutton
+from spinint import spinint
+from selection import selection
+import char
+import checkbox
+from reference import reference
+import rpc
+
+class char(char.char):
+ def __init__(self, name, parent, attrs={}):
+ super(char,self).__init__(name, parent)
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')],
+ ['=', _('is Empty')],
+ ['<>',_('is not Empty')],
+ ['ilike', _('contains')],
+ ['not ilike', _('doesn\'t contain')])
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+
+ def _value_get(self):
+ if self.selected_oper_text in ['is Empty', 'is not Empty']:
+ text = False
+ else:
+ text = self.widget.get_text()
+ return [(self.field_left, self.selected_oper, text)]
+
+ def set_visibility(self):
+ self.widget.show_all()
+ self.widget.set_text('')
+ if self.selected_oper_text in ['is Empty', 'is not Empty']:
+ self.widget.hide()
+
+class many2one(wid_int.wid_int):
+ def __init__(self, name, parent, attrs={}):
+ wid_int.wid_int.__init__(self, name, parent)
+ self.attrs = attrs
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')],
+ ['=', _('is Empty')],
+ ['<>',_('is not Empty')],
+ ['ilike', _('contains')],
+ ['not ilike', _('doesn\'t contain')])
+
+ self.widget = gtk.HBox(spacing=0)
+ self.widget.set_property('sensitive', True)
+
+ self.wid_text = gtk.Entry()
+ self.wid_text.set_property('width-chars', 20)
+ self.wid_text.connect('key_press_event', self.sig_key_press)
+ self.wid_text.connect_after('activate', self.sig_activate)
+ self.widget.pack_start(self.wid_text, expand=True, fill=True)
+
+ self.but_find = gtk.Button()
+ img = gtk.Image()
+ img.set_from_stock('gtk-find', gtk.ICON_SIZE_BUTTON)
+ self.but_find.set_image(img)
+ self.but_find.set_relief(gtk.RELIEF_NONE)
+ self.but_find.connect('clicked', self.sig_find)
+ self.but_find.set_alignment(0.5, 0.5)
+ self.but_find.set_property('can-focus', False)
+ self.but_find.set_tooltip_text(_('Search a resource'))
+ self.but_find.set_size_request(30,30)
+ self.widget.pack_start(self.but_find, padding=2, expand=False, fill=False)
+
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+ self.enter_pressed = False
+ self.selected_value = False
+
+ def sig_activate(self, widget, event=None, leave=False):
+ if not self.selected_oper_text in ['contains', 'doesn\'t contain']:
+ event = self.enter_pressed and True or event
+ return self.sig_find(widget, event, leave=True)
+
+ def sig_find(self, widget, event=None, leave=True):
+ from modules.gui.window.win_search import win_search
+ name_search = self.wid_text.get_text() or ''
+ ids = rpc.session.rpc_exec_auth('/object', 'execute', self.attrs['relation'], 'name_search', name_search, [], 'ilike', rpc.session.context)
+ win = win_search(self.attrs['relation'], sel_multi=False, ids=map(lambda x: x[0], ids), context=rpc.session.context, parent=self.parent)
+ win.glade.get_widget('newbutton').hide()
+ ids = win.go()
+ if ids:
+ self.selected_value = rpc.session.rpc_exec_auth('/object', 'execute', self.attrs['relation'], 'name_get', [ids[0]], rpc.session.context)[0]
+ self.wid_text.set_text(self.selected_value[1])
+ return
+
+ def sig_key_press(self, widget, event, *args):
+ self.enter_pressed = False
+ if event.keyval == gtk.keysyms.F2:
+ self.sig_activate(widget, event)
+ elif event.keyval == gtk.keysyms.Tab:
+ if not self.wid_text.get_text():
+ return False
+ return not self.sig_activate(widget, event, leave=True)
+ elif event.keyval in (gtk.keysyms.KP_Enter,gtk.keysyms.Return):
+ if self.wid_text.get_text():
+ self.enter_pressed = True
+ return False
+
+ def _value_get(self):
+ if self.selected_oper_text in ['is', 'is not']:
+ text = self.selected_value and self.selected_value[0] or False
+ elif self.selected_oper_text in ['is Empty', 'is not Empty']:
+ text = False
+ else:
+ text = self.wid_text.get_text()
+ return [(self.field_left, self.selected_oper, text)]
+
+ def set_visibility(self):
+ self.widget.show_all()
+ self.wid_text.set_text('')
+ self.selected_value = False
+ if self.selected_oper_text in ['is Empty', 'is not Empty']:
+ self.wid_text.hide()
+ self.but_find.hide()
+ elif not self.selected_oper_text in ['is', 'is not']:
+ self.but_find.hide()
+
+class one2many(many2one):
+ def __init__(self, name, parent, attrs={}):
+ many2one.__init__(self, name, parent, attrs)
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')],
+ ['=', _('is Empty')],
+ ['<>',_('is not Empty')])
+class many2many(many2one):
+ def __init__(self, name, parent, attrs={}):
+ many2one.__init__(self, name, parent, attrs)
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')],
+ ['=', _('is Empty')],
+ ['<>',_('is not Empty')])
+
+
+class checkbox(wid_int.wid_int):
+ def __init__(self, name, parent, attrs={}):
+ wid_int.wid_int.__init__(self, name, parent)
+ self.widget = gtk.CheckButton()
+ self.widget.set_active(False)
+ self.operators = (['=', _('Equals')],)
+ self.selected_oper = False
+ self.field_left = False
+
+ def _value_get(self):
+ return [(self.field_left, self.selected_oper, int(self.widget.get_active()))]
+
+ def set_visibility(self):
+ pass
+
+class calendar(calendar):
+ def __init__(self, name, parent, attrs={}):
+ super(calendar,self).__init__(name, parent)
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')],
+ ['*', _('between')],
+ ['=', _('is Empty')],
+ ['<>',_('is not Empty')],
+ ['**', _('exclude range')])
+
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+
+ def _value_get(self):
+ val1 = self._date_get(self.entry1.get_text())
+ val2 = self._date_get(self.entry2.get_text())
+ if self.selected_oper_text == 'between':
+ domain = ['&', (self.field_left, '>=', val1),(self.field_left, '<=', val2)]
+ return domain
+ elif self.selected_oper_text == 'exclude range':
+ domain = ['|',(self.field_left, '<', val1),(self.field_left, '>', val2)]
+ return domain
+ elif self.selected_oper_text in ['is Empty', 'is not Empty']:
+ val1 = False
+ domain = [(self.field_left, self.selected_oper, val1)]
+ return domain
+
+ def set_visibility(self):
+ self.entry1.set_text(self.widget1.widget.initial_value)
+ self.entry2.set_text(self.widget2.widget.initial_value)
+ if self.selected_oper_text in ['is Empty', 'is not Empty']:
+ self.widget.hide_all()
+ elif self.selected_oper_text in ['is', 'is not']:
+ self.widget.show_all()
+ self.entry1.show()
+ self.entry2.hide()
+ self.label.hide()
+ self.eb1.show()
+ self.eb2.hide()
+ else:
+ self.widget.show_all()
+
+class datetime(datetime):
+ def __init__(self, name, parent, attrs={}):
+ super(datetime,self).__init__(name, parent)
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')],
+ ['*', _('between')],
+ ['=', _('is Empty')],
+ ['<>',_('is not Empty')],
+ ['**', _('exclude range')])
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+
+ def _value_get(self):
+ val1 = self._date_get(self.entry1.get_text())
+ val2 = self._date_get(self.entry2.get_text())
+ if self.selected_oper_text == 'between':
+ domain = ('&', (self.field_left, '>=', val1),(self.field_left, '<=', val2))
+ return domain
+ elif self.selected_oper_text == 'exclude range':
+ domain = ('|',(self.field_left, '<', val1),(self.field_left, '>', val2))
+ return domain
+ elif self.selected_oper_text in ['is Empty', 'is not Empty']:
+ val1 = False
+ domain = [(self.field_left, self.selected_oper, val1)]
+ return domain
+
+ def set_visibility(self):
+ self.entry1.set_text(self.widget1.widget.initial_value)
+ self.entry2.set_text(self.widget2.widget.initial_value)
+ if self.selected_oper_text in ['is Empty', 'is not Empty']:
+ self.widget.hide_all()
+ elif self.selected_oper_text in ['is', 'is not']:
+ self.widget.show_all()
+ self.entry1.show()
+ self.entry2.hide()
+ self.label.hide()
+ self.eb1.show()
+ self.eb2.hide()
+ else:
+ self.widget.show_all()
+
+
+class selection(selection):
+ def __init__(self, name, parent, attrs={}):
+ selection_dict = {'selection':attrs.get('selection', {})}
+ super(selection,self).__init__(name, parent, selection_dict)
+ self.operators = (['=', _('is')],
+ ['<>',_('is not')])
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+
+ def _value_get(self):
+ key = self._selection.get(self.widget.child.get_text(), False)
+ return [(self.field_left, self.selected_oper, key)]
+
+ def set_visibility(self):
+ self.widget.child.set_text('')
+ pass
+
+#
+class spinbutton(spinbutton):
+ def __init__(self, name, parent, attrs={}):
+ super(spinbutton,self).__init__(name, parent)
+ self.operators = (['=', _('is equal to')],
+ ['<>',_('is not equal to')],
+ ['>',_('greater than')],
+ ['<',_('less than')],
+ ['>=',_('greater than equal to')],
+ ['<=',_('less than equal to')],
+ ['*',_('between')],
+ ['**',_('exclude range')])
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+
+ def _value_get(self):
+ self.spin1.update()
+ self.spin2.update()
+ val1 = self.spin1.get_value()
+ val2 = self.spin2.get_value()
+ if self.selected_oper_text == 'between':
+ domain = ('&', (self.field_left, '>=', val1),(self.field_left, '<=', val2))
+ return domain
+ elif self.selected_oper_text == 'exclude range':
+ domain = ('|',(self.field_left, '<', val1),(self.field_left, '>', val2))
+ return domain
+ domain = [(self.field_left, self.selected_oper, val1)]
+ return domain
+
+ def set_visibility(self):
+ self.spin1.set_value(0.0)
+ self.spin2.set_value(0.0)
+ if self.selected_oper_text in ['between', 'exclude range']:
+ self.widget.show_all()
+ else:
+ self.spin2.hide()
+ self.label.hide()
+
+class spinint(spinint):
+ def __init__(self, name, parent, attrs={}):
+ super(spinint,self).__init__(name, parent)
+ self.operators = (['=', _('is equal to')],
+ ['<>',_('is not equal to')],
+ ['>',_('greater than')],
+ ['<',_('less than')],
+ ['>=',_('greater than equal to')],
+ ['<=',_('less than equal to')],
+ ['*',_('between')],
+ ['**',_('exclude range')])
+ self.selected_oper = False
+ self.selected_oper_text = False
+ self.field_left = False
+
+ def _value_get(self):
+ self.spin1.update()
+ self.spin2.update()
+ val1 = self.spin1.get_value()
+ val2 = self.spin2.get_value()
+ if self.selected_oper_text == 'between':
+ domain = ('&', (self.field_left, '>=', val1),(self.field_left, '<=', val2))
+ return domain
+ elif self.selected_oper_text == 'exclude range':
+ domain = ('|',(self.field_left, '<', val1),(self.field_left, '>', val2))
+ return domain
+ domain = [(self.field_left, self.selected_oper, val1)]
+ return domain
+
+ def set_visibility(self):
+ val1 = self.spin1.set_value(0)
+ val2 = self.spin2.set_value(0)
+ if self.selected_oper_text in ['between', 'exclude range']:
+ self.widget.show_all()
+ else:
+ self.spin2.hide()
+ self.label.hide()
+
+widgets_type = {
+ 'date': calendar,
+ 'datetime': datetime,
+ 'float': spinbutton,
+ 'integer': spinint,
+ 'selection': selection,
+ 'char': char,
+ 'boolean': checkbox,
+ 'text': char,
+ 'many2one':many2one,
+ 'one2many':one2many,
+ 'many2many':many2many,
+ }
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
=== modified file 'bin/widget_search/date_widget.py'
--- bin/widget_search/date_widget.py 2011-01-31 14:48:39 +0000
+++ bin/widget_search/date_widget.py 2011-02-23 10:37:57 +0000
@@ -23,7 +23,7 @@
import pango
import gtk
import re
-
+from datetime import datetime
import tools
import tools.datetime_util
import time
@@ -38,8 +38,8 @@
for key,val in tools.datetime_util.date_mapping.items():
self.regex = self.regex.replace(key, val[1])
self.initial_value = self.initial_value.replace(key, val[0])
-
- self.small_text = self.initial_value
+
+ self.small_text = self.initial_value
self.set_text(self.initial_value)
self.regex = re.compile(self.regex)
@@ -73,13 +73,13 @@
('%U',''), ('%W','')]:
fmt = fmt.replace(x, y)
- if (not (fmt.count('%Y') >= 1 and fmt.count('%m') >= 1 and fmt.count('%d') >= 1) or fmt.count('%x') >= 1) and (fmt.count('%H') == 0 and fmt.count('%M') == 0 and fmt.count('%S') == 0 and fmt.count('%X') == 0):
-
+ if (not (fmt.count('%Y') >= 1 and fmt.count('%m') >= 1 and fmt.count('%d') >= 1) or fmt.count('%x') >= 1) and (fmt.count('%H') == 0 and fmt.count('%M') == 0 and fmt.count('%S') == 0 and fmt.count('%X') == 0):
+
return '%Y/%m/%d'
elif not (fmt.count('%Y') >= 1 and fmt.count('%m') >= 1 and fmt.count('%d') >= 1) \
or (fmt.count('%x') >=1 or fmt.count('%c') >= 1):
return '%Y/%m/%d %H:%M:%S'
-
+
return fmt
@@ -89,14 +89,14 @@
return datetime.strptime(text, self.format)
except:
pass
-
+
try:
return datetime.strptime(text, self.small_format)
except:
self.valid = False
return False
-
-
+
+
def _on_insert_text(self, editable, value, length, position):
if not self._interactive_input:
return
@@ -104,14 +104,14 @@
self.stop_emission('insert-text')
if self.mode_cmd:
if self.callback: self.callback(value)
- return
-
- text = self.get_text()
+ return
+
+ text = self.get_text()
current_pos = self.get_position()
-
+
if(length + current_pos > len(text)):
return
-
+
pos = (current_pos < 10 or text != self.initial_value) and current_pos or 0
if length != 1:
@@ -156,7 +156,7 @@
if self.mode_cmd:
self.mode_cmd = False
if self.callback_process: self.callback_process(False, self, False)
-
+
def _focus_in(self, args, args2):
self.set_text(self.small_text)
if self.mode_cmd:
@@ -170,10 +170,10 @@
date = self.isvalid_date(text);
if(date):
self.small_text = date.strftime(self.small_format)
-
+
finally:
self._interactive_input = True
-
+
def date_set(self, dt):
if dt:
self.set_text( dt.strftime(self.format) )
=== modified file 'bin/widget_search/form.py'
--- bin/widget_search/form.py 2011-02-01 09:45:54 +0000
+++ bin/widget_search/form.py 2011-02-23 10:37:57 +0000
@@ -28,6 +28,7 @@
import tools
from lxml import etree
import uuid
+import copy
class _container(object):
def __init__(self, max_width):
@@ -316,6 +317,7 @@
self.show()
for x in self.widgets.values():
x[0].sig_activate(self.sig_activate)
+ self.invisible_widgets = []
def xml_process(self,xml_arch):
root = etree.fromstring(xml_arch)
@@ -364,15 +366,32 @@
def remove_custom(self, button, panel):
button.parent.destroy()
# Removing the Destroyed widget from Domain calculation
- for element in self.custom_widgets.keys():
- if self.custom_widgets[element][0] == panel:
- del self.custom_widgets[element]
- break
+ ## also removing the field from the list of invisible fields
+ ## so that they dont reappear and as the childs are deleted for the panel
+ ## that has to be deleted we need to do a reverse process for removing the
+ ## the invisible fields from the list of invisible fields.
+ def process(widget):
+ if isinstance(widget, gtk.HBox):
+ for child in widget.get_children():
+ process(child)
+ inv_childs = self.invisible_widgets
+ for inv_child in inv_childs:
+ if inv_child != widget:
+ self.invisible_widgets.remove(inv_child)
+ return True
+
+ custom_panel = copy.copy(self.custom_widgets)
+ for key, wid in custom_panel.iteritems():
+ for child in wid[0].widget.get_children():
+ if not isinstance(child, (gtk.ComboBox, gtk.Button)):
+ process(child)
+ if wid[0] == panel:
+ del self.custom_widgets[key]
return True
def add_custom(self, widget, table, fields):
new_table = gtk.Table(1,1,False)
- panel = widgets_type['custom_filter'][0]('', self.parent,{'fields':fields},call=self.remove_custom)
+ panel = widgets_type['custom_filter'][0]('', self.parent, fields, callback=self.remove_custom)
x = self.rows
new_table.attach(panel.widget,0, 1, x, x+1, xoptions=gtk.FILL, yoptions=gtk.FILL , ypadding=2, xpadding=0)
panelx = 'panel' + str(x)
@@ -380,7 +399,29 @@
self.custom_widgets[panelx] = (panel, new_table, 1)
table.attach(new_table, 1, 9, x, x+1)
self.rows += 1
+ ## Store the widgets original visible attribute becuase as they are
+ ## attached to the table as a child widgets and the table.show_all() will
+ ## set all child widgets to visible inspite of their visibility is set to FALSE
+ ## so make them invisible again after the table.show_all()
+ def process(widget):
+ if isinstance(widget, gtk.HBox):
+ for sub_child in widget.get_children():
+ process(sub_child)
+ if widget.get_visible():
+ if widget in self.invisible_widgets:
+ self.invisible_widgets.remove(widget)
+ else:
+ if not widget in self.invisible_widgets:
+ self.invisible_widgets.append(widget)
+ return True
+
+ for key, wid in self.custom_widgets.iteritems():
+ for child in wid[0].widget.get_children():
+ if not isinstance(child, (gtk.ComboBox, gtk.Button)):
+ process(child)
table.show_all()
+ for wid in self.invisible_widgets:
+ wid.set_visible(False)
return panel
def toggle(self, widget, event=None):
@@ -413,12 +454,16 @@
if self.groupby:
context.update({'group_by':self.groupby})
if domain:
- if len(domain)>1 and domain[-2] in ['&','|']:
- if len(domain) == 2:
- domain = [domain[1]]
+ if '&' in domain or '|' in domain:
+ if domain[-2] in ['&','|']:
+ pos = 2
+ elif len(domain) >= 4 and domain[-4] in ['&','|']:
+ pos = 4
+ if len(domain) == 2 or len(domain) == 4:
+ domain = domain[1:]
else:
- res1 = domain[:-2]
- res2 = domain[-1:]
+ res1 = domain[:-pos]
+ res2 = domain[-(pos-1):]
domain = res1 + res2
return {'domain':domain, 'context':context}
=== modified file 'bin/widget_search/spinbutton.py'
--- bin/widget_search/spinbutton.py 2011-01-31 10:28:17 +0000
+++ bin/widget_search/spinbutton.py 2011-02-23 10:37:57 +0000
@@ -39,8 +39,8 @@
self.spin1.connect('input', self.format_input)
self.spin1.connect('output', self.format_output)
self.widget.pack_start(self.spin1, expand=False, fill=True)
-
- self.widget.pack_start(gtk.Label('-'), expand=False, fill=False)
+ self.label = gtk.Label('-')
+ self.widget.pack_start(self.label, expand=False, fill=False)
adj2 = gtk.Adjustment(0.0, -sys.maxint, sys.maxint, 1.0, 5.0)
self.spin2 = gtk.SpinButton(adj2, 1.0, digits=int(attrs.get('digits', (14, 2))[1]))
=== modified file 'bin/widget_search/spinint.py'
--- bin/widget_search/spinint.py 2011-01-31 10:28:17 +0000
+++ bin/widget_search/spinint.py 2011-02-23 10:37:57 +0000
@@ -43,8 +43,8 @@
self.spin1.connect('input', self.format_input)
self.spin1.connect('output', self.format_output)
self.widget.pack_start(self.spin1, expand=False, fill=True)
-
- self.widget.pack_start(gtk.Label('-'), expand=False, fill=False)
+ self.label = gtk.Label('-')
+ self.widget.pack_start(self.label, expand=False, fill=False)
adj2 = gtk.Adjustment(0.0, 0.0, sys.maxint, 1.0, 5.0)
self.spin2 = gtk.SpinButton(adj2, 1, digits=0)
_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help : https://help.launchpad.net/ListHelp