def _testValidDataType(self): entry = ProxyEntry() entry.set_property("data-type", "date") # let's make the entry complain! entry.set_text("string") self.assertEqual(entry.read(), ValueUnset) self.assertNotEqual(entry._complaint_checker_id, -1) # now let's put proper data entry.set_text(self.date_format) date = datatypes.date2str(entry.read()) self.assertEqual(date, self.date_format) self.assertEqual(entry._background_timeout_id, -1) locale_dictionary = datatypes.locale_dictionary # now change the data-type and do it again entry.set_property("data-type", "float") if locale_dictionary["thousands_sep"] == ',': # correct value entry.set_text("23,400,000.2") self.assertEqual(entry.read(), 23400000.2) self.assertEqual(entry._background_timeout_id, -1) # wrong value entry.set_text("23.400.000,2") self.assertEqual(entry.read(), ValueUnset)
def __init__(self): gtk.HBox.__init__(self) self._popping_down = False self._old_date = None # bootstrap problems, kiwi.ui.widgets.entry imports dateentry # we need to use a proxy entry because we want the mask from kiwi.ui.widgets.entry import ProxyEntry self.entry = ProxyEntry() self.entry.connect('changed', self._on_entry__changed) self.entry.connect('activate', self._on_entry__activate) self.entry.set_property('data-type', datetime.date) mask = self.entry.get_mask() if mask: self.entry.set_width_chars(len(mask)) self.pack_start(self.entry, False, False) self.entry.show() self._button = gtk.ToggleButton() self._button.connect('scroll-event', self._on_entry__scroll_event) self._button.connect('toggled', self._on_button__toggled) self._button.set_focus_on_click(False) self.pack_start(self._button, False, False) self._button.show() arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE) self._button.add(arrow) arrow.show() self._popup = _DateEntryPopup(self) self._popup.connect('date-selected', self._on_popup__date_selected) self._popup.connect('hide', self._on_popup__hide) self._popup.set_size_request(-1, 24)
def _setup_entry_slave(self, box=None): widget = ProxyEntry() # Try to simulate insensitive appearance for non-editable entries # while keeping them selectable widget.set_editable(self.sensitive) if not self.sensitive: style = widget.get_style() widget.modify_text(gtk.STATE_NORMAL, style.text[gtk.STATE_INSENSITIVE]) widget.modify_base(gtk.STATE_NORMAL, style.base[gtk.STATE_INSENSITIVE]) widget.data_type = unicode widget.model_attribute = "field_value" self.proxy.add_widget("field_value", widget) if box is None: self.container.add(widget) else: box.pack_start(widget) widget.show() widget.connect('validate', self._on_entry__validate) widget.connect('validation-changed', self._on_entry__validation_changed) self._entry = widget
def testDigitMask(self): e = ProxyEntry() e.set_mask('000.000') self.assertEqual(e.get_text(), ' . ') e.set_text('123.456') self.assertEqual(e.get_text(), '123.456') e.delete_text(0, 2) self.assertEqual(e.get_text(), '345.6 ')
def add_entry(self, data_type): """Add a entry with the specified data_type The user will be able to provide any information in the entry that should be used by this operation (for instance, a number do multiply a value for or a string to replace a value for) """ entry = ProxyEntry(data_type=data_type) self.pack_start(entry, False, False, 0) return entry
def testIdleAddedProperly(self): entry = ProxyEntry() entry.set_property("data-type", "int") while Gtk.events_pending(): Gtk.main_iteration() self.assertEqual(entry.get_property('data_type'), 'int') entry = ProxyEntry(data_type=str) while Gtk.events_pending(): Gtk.main_iteration() self.assertEqual(entry.get_property('data_type'), 'str') entry.set_property("data-type", int) self.assertEqual(entry.get_property('data_type'), 'int') entry = ProxyEntry(data_type=str) self.assertEqual(entry.get_property('data_type'), 'str') entry.set_property("data-type", int) while Gtk.events_pending(): Gtk.main_iteration() self.assertEqual(entry.get_property('data_type'), 'int')
def _create_interface(self, run_editor=None): self.sale = self.create_sale() self.window = Gtk.Window() self.entry = ProxyEntry() self.window.add(self.entry) self.client_gadget = SearchEntryGadget( self.entry, self.store, model=self.sale, model_property='client', search_columns=['name'], search_class=ClientSearch, parent=self.window, run_editor=run_editor) self.client_gadget.get_model_obj = lambda obj: obj and obj.client
def get_main_widget(self): # This is done on entry to check where to put the validation/mandatory # icons. We should put the calculator on the other side. # Note that spinbuttons are always right aligned and thus # xalign will always be 1.0 if self.attached_widget.get_alignment() > 0.5: self._icon_pos = 'secondary-icon' else: self._icon_pos = 'primary-icon' self.attached_widget.set_property(self._icon_pos + '-activatable', True) self.attached_widget.set_property( self._icon_pos + '-tooltip-text', _("Do calculations on top of this value")) self.attached_widget.connect('notify::sensitive', self._on_entry_sensitive__notify) self.attached_widget.connect('icon-press', self._on_entry__icon_press) self._toggle_calculator_icon() vbox = Gtk.VBox(spacing=6) vbox.show() self._main_label = Gtk.Label() self._main_label.set_ellipsize(Pango.EllipsizeMode.END) vbox.pack_start(self._main_label, True, True, 0) self._main_label.show() self._entry = ProxyEntry() # FIXME: We need a model_attribute here or else the entry.is_valid() # will always return None. Check proxywidget.py's FIXME to see why self._entry.model_attribute = 'not_used' self._entry.connect('validate', self._on_entry__validate) self._entry.connect_after('changed', self._after_entry__changed) self._entry.set_alignment(1.0) vbox.pack_start(self._entry, True, True, 0) self._entry.show() hbox = Gtk.HBox(spacing=6) vbox.pack_start(hbox, True, True, 0) hbox.show() self._label = Gtk.Label() self._label.set_property('xalign', 1.0) self._label.set_use_markup(True) hbox.pack_start(self._label, True, True, 0) self._label.show() self._warning = Gtk.Image() hbox.pack_start(self._warning, False, False, 0) return vbox
def build_widget(self): if self.editable: widget = ProxyEntry() if self.max_length != 0: widget.set_width_chars(self.max_length) if self.input_mask: widget.set_mask(self.input_mask) else: widget = ProxyLabel() # This label should be left aligned. widget.set_alignment(0, 0.5) return widget
def test_create(self): window = Gtk.Window() box = Gtk.VBox() window.add(box) entry = ProxyEntry() box.pack_start(entry, True, True, 0) self.check_dialog(window, 'search-entry-before-replace') sale = self.create_sale() SearchEntryGadget(entry, self.store, model=sale, model_property='client', search_columns=['name'], search_class=ClientSearch, parent=window) self.check_dialog(window, 'search-entry-after-replace')
def _create_interface(self): self.sale = self.create_sale() self.window = gtk.Window() self.entry = ProxyEntry() self.window.add(self.entry) self.client_gadget = SearchEntryGadget(self.entry, self.store, model=self.sale, model_property='client', search_columns=['name'], search_class=ClientSearch, parent=self.window)
def test_popup(self): entry = ProxyEntry() entry.data_type = currency entry.set_text('150') calc = CalculatorPopup(entry, CalculatorPopup.MODE_SUB) event = Gdk.Event.new(Gdk.EventType.BUTTON_PRESS) event.window = Gdk.get_default_root_window() with mock.patch.object(calc, 'popup') as popup: entry.emit('icon-press', Gtk.EntryIconPosition.PRIMARY, event) self.assertEqual(popup.call_count, 0) entry.emit('icon-press', Gtk.EntryIconPosition.SECONDARY, event) self.assertEqual(popup.call_count, 1)
def testRead(self): # int without mask entry = ProxyEntry() entry.set_text('1') entry.set_property("data-type", "int") self.assertEqual(entry.read(), 1) entry.set_text('') # empty int reads as ValueUnset self.assertEqual(entry.read(), ValueUnset) # int with mask entry = ProxyEntry() entry.set_property("data-type", "int") entry.set_mask('00') entry.set_text('12') self.assertEqual(entry.read(), 12) entry.set_text('') # empty int reads as ValueUnset self.assertEqual(entry.read(), ValueUnset) # str without mask entry = ProxyEntry() entry.set_property("data-type", "str") entry.set_text('123') self.assertEqual(entry.read(), '123') entry.set_text('') self.assertEqual(entry.read(), '') # str with mask entry = ProxyEntry() entry.set_property("data-type", "str") entry.set_mask('00-00.00') entry.set_text('123456') self.assertEqual(entry.read(), '12-34.56') entry.set_text('') self.assertEqual(entry.read(), '')
def test_apply(self): entry = ProxyEntry() entry.data_type = currency entry.set_text('150') calc = CalculatorPopup(entry, CalculatorPopup.MODE_SUB) # calc.popup will not work here, so call validate_popup directly calc.validate_popup() calc._entry.set_text('10%') event = Gdk.Event.new(Gdk.EventType.KEY_PRESS) event.keyval = Gdk.KEY_Return event.window = Gdk.get_default_root_window() calc.emit('key-press-event', event) calc.emit('key-press-event', event) self.assertEqual(entry.read(), 135)
def __init__(self): super(DateEntry, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) self.get_style_context().add_class(Gtk.STYLE_CLASS_LINKED) self._popping_down = False self._old_date = None self._block_changed = False # This will force both the entry and the button have the same height self._sizegroup = Gtk.SizeGroup.new(Gtk.SizeGroupMode.VERTICAL) # bootstrap problems, kiwi.ui.widgets.entry imports dateentry # we need to use a proxy entry because we want the mask from kiwi.ui.widgets.entry import ProxyEntry self.entry = ProxyEntry() # Set datatype before connecting to change event, to not get when the # mask is set self.entry.set_property('data-type', datetime.date) self.entry.connect('changed', self._on_entry__changed) self.entry.connect('activate', self._on_entry__activate) mask = self.entry.get_mask() if mask: self.entry.set_width_chars(len(mask)) self.pack_start(self.entry, True, True, 0) self.entry.set_valign(Gtk.Align.CENTER) self._sizegroup.add_widget(self.entry) self.entry.show() self._button = Gtk.ToggleButton() self._button.set_valign(Gtk.Align.CENTER) self._button.connect('scroll-event', self._on_entry__scroll_event) self._button.connect('toggled', self._on_button__toggled) self._button.set_focus_on_click(False) self.pack_start(self._button, False, False, 0) self._sizegroup.add_widget(self._button) self._button.show() arrow = Gtk.Arrow(arrow_type=Gtk.ArrowType.DOWN, shadow_type=Gtk.ShadowType.NONE) self._button.add(arrow) arrow.show() self._popup = _DateEntryPopup(self) self._popup.connect('date-selected', self._on_popup__date_selected) self._popup.connect('hide', self._on_popup__hide) self._popup.set_size_request(-1, 24) self.set_valign(Gtk.Align.CENTER)
def _setup_entry_slave(self, box=None): widget = ProxyEntry() widget.props.sensitive = self.sensitive widget.data_type = unicode widget.model_attribute = "field_value" self.proxy.add_widget("field_value", widget) if box is None: self.container.add(widget) else: box.pack_start(widget) widget.show() widget.connect('validate', self._on_entry__validate) widget.connect('validation-changed', self._on_entry__validation_changed) self._entry = widget
def _create_entry(self, mandatory=False): entry = ProxyEntry() entry.data_type = str # Set as empty or kiwi will return ValueUnset on entry.read() # and we would have to take that in consideration everywhere here entry.update(u'') entry.mandatory = mandatory self.setup_entry(entry) entry.connect_after('content-changed', self._after_entry__content_changed) entry.connect_after('changed', self._after_entry__changed) entry.connect('validate', self._on_entry__validate) entry.connect('activate', self._on_entry__activate) return entry
def test_with_cfop(self, run_dialog, new_store): new_store.return_value = self.store window = Gtk.Window() entry = ProxyEntry() window.add(entry) sale = self.create_sale() gadget = SearchEntryGadget( entry, self.store, model=sale, model_property='cfop', search_columns=['name'], search_class=CfopSearch, parent=window) with mock.patch.object(self.store, 'commit'): with mock.patch.object(self.store, 'close'): run_dialog.return_value = None self.click(gadget.edit_button) run_dialog.assert_called_once_with( CfopEditor, window, self.store, sale.cfop)
def _setup_widgets(self): # Hide total and subtotal self.table1.hide() self.hbox4.hide() # Hide invoice number details self.invoice_number_label.hide() self.invoice_number.hide() # Hide cost center combobox self.cost_center_lbl.hide() self.cost_center.hide() # Responsible combo self.salesperson_lbl.set_text(_(u'Responsible:')) self.salesperson.model_attribute = 'responsible' users = self.store.find(LoginUser, is_active=True) self.salesperson.prefill(api.for_person_combo(users)) self.salesperson.set_sensitive(False) self._fill_clients_combo() self._fill_clients_category_combo() self.expire_date.mandatory = True # CFOP combo self.cfop_lbl.hide() self.cfop.hide() self.create_cfop.hide() # Transporter/RemovedBy Combo self.transporter_lbl.set_text(_(u'Removed By:')) self.create_transporter.hide() # removed_by widget self.removed_by = ProxyEntry(unicode) self.removed_by.model_attribute = 'removed_by' if 'removed_by' not in self.proxy_widgets: self.proxy_widgets.append('removed_by') self.removed_by.show() self._replace_widget(self.transporter, self.removed_by) # Operation Nature widget self.operation_nature.hide() self.nature_lbl.hide()
def test_popdown(self): entry = ProxyEntry() entry.data_type = currency entry.set_text('150') calc = CalculatorPopup(entry, CalculatorPopup.MODE_SUB) with contextlib.nested( mock.patch.object(calc, '_maybe_apply_new_value'), mock.patch.object(calc, 'popdown')) as (manv, popdown): # Those keys should try to apply the value for keyval in [ gtk.keysyms.Return, gtk.keysyms.KP_Enter, gtk.keysyms.Tab ]: event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) event.keyval = keyval event.window = gtk.gdk.get_default_root_window() calc.emit('key-press-event', event) self.assertEqual(manv.call_count, 1) self.assertEqual(popdown.call_count, 0) manv.reset_mock() popdown.reset_mock() event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) # Escape should popdown the popup event.keyval = gtk.keysyms.Escape event.window = gtk.gdk.get_default_root_window() calc.emit('key-press-event', event) self.assertEqual(popdown.call_count, 1) self.assertEqual(manv.call_count, 0) manv.reset_mock() popdown.reset_mock() event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) # Any other should not do anything event.keyval = gtk.keysyms.A event.window = gtk.gdk.get_default_root_window() calc.emit('key-press-event', event) self.assertEqual(manv.call_count, 0) self.assertEqual(popdown.call_count, 0)
def testDataMode(self): entry = ProxyEntry() entry.data_type = str entry.set_exact_completion() items = {'xxx': object(), 'yyy': object()} entry.prefill([(k, v) for k, v in items.items()]) entry.set_text('xxx') self.assertIs(entry.read(), items['xxx']) entry.set_text('x') self.assertIs(entry.read(), None) entry.set_text('xxxxx') self.assertIs(entry.read(), None) entry.set_text('yyy') self.assertIs(entry.read(), items['yyy']) entry.set_text('y') self.assertIs(entry.read(), None) entry.set_text('yyyyy') self.assertIs(entry.read(), None)
def get_widget_for_type(rtype): if rtype is types.boolean: return ProxyCheckButton() elif rtype is types.file: w = ProxyFileChooserButton('Select File') #w.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) return w elif rtype is types.readonlyfile: w = ProxyFileChooserButton('Select File') w.set_sensitive(False) #w.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) return w elif rtype in [types.directory]: w = ProxyFileChooserButton(title='Select Directory') w.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) return w elif rtype is types.font: return ProxyFontButton() elif rtype is types.color: return CleverProxyColorButton() elif rtype is types.integer: w = ProxySpinButton() return w elif rtype.__name__ is 'intrange': adjvals = rtype.lower, rtype.upper, rtype.step adj = gtk.Adjustment(0, *adjvals) w = ProxySpinButton() w.set_adjustment(adj) return w elif rtype is types.readonly: return FormattedLabel(VC_NAME_MU) elif rtype.__name__ is 'stringlist': w = ProxyComboBox() w.set_property('data-type', str) w.prefill(rtype.choices) return w else: w = ProxyEntry(data_type=str) w.set_width_chars(18) return w
def _setup_entry_slave(self, box=None): widget = ProxyEntry() # Try to simulate insensitive appearance for non-editable entries # while keeping them selectable widget.set_editable(self.sensitive) if not self.sensitive: sc = widget.get_style_context() sc.add_class('visualmode') widget.data_type = str widget.model_attribute = "field_value" self.proxy.add_widget("field_value", widget) if box is None: self.container.add(widget) else: box.pack_start(widget, True, True, 0) widget.show() widget.connect('validate', self._on_entry__validate) widget.connect('validation-changed', self._on_entry__validation_changed) self._entry = widget
def _setup_widgets(self): # Hide total and subtotal self.summary_table.hide() self.total_box.hide() # Hide cost center combobox self.cost_center_lbl.hide() self.cost_center.hide() # Responsible combo self.salesperson_lbl.set_text(_(u'Responsible:')) self.salesperson.model_attribute = 'responsible' users = self.store.find(LoginUser, is_active=True) self.salesperson.prefill(stoq_api.for_person_combo(users)) self.salesperson.set_sensitive(False) self._setup_clients_widget() self._fill_clients_category_combo() self.expire_date.mandatory = True # CFOP combo self.cfop_lbl.hide() self.cfop.hide() self.create_cfop.hide() # Transporter/RemovedBy Combo self.transporter_lbl.set_text(_(u'Removed By:')) self.create_transporter.hide() # removed_by widget self.removed_by = ProxyEntry(str) self.removed_by.model_attribute = 'removed_by' if 'removed_by' not in self.proxy_widgets: self.proxy_widgets.append('removed_by') self.removed_by.show() self._replace_widget(self.transporter, self.removed_by)
def test_validate(self): def validate_entry(entry, value): if value == 100: return ValidationError() # FIXME: For some reason, entry is not emitting 'changed' event # on set_text, not even if we call entry.emit('changed') by hand. # That only happens here on the test. Figure out why def update_entry(entry, value): entry.set_text(value) entry.validate(force=True) entry = ProxyEntry() entry.data_type = currency entry.connect('validate', validate_entry) entry.set_text('150') calc = CalculatorPopup(entry, CalculatorPopup.MODE_SUB) # calc.popup will not work here, so call validate_popup directly calc.validate_popup() self.assertValid(calc, ['_entry']) self.assertNotVisible(calc, ['_warning']) for value in ['abc', '+10%', '-10%', '+10', '-10']: update_entry(calc._entry, value) self.assertInvalid(calc, ['_entry']) self.assertNotVisible(calc, ['_warning']) update_entry(calc._entry, '40') self.assertValid(calc, ['_entry']) self.assertNotVisible(calc, ['_warning']) # 50 of discount will make the value invalid on entry # (see validate_entry above) update_entry(calc._entry, '50') self.assertValid(calc, ['_entry']) self.assertVisible(calc, ['_warning'])
def test_attach(self): entry = ProxyEntry() entry.data_type = currency self.assertEqual(entry.get_property('secondary-icon-pixbuf'), None) calc = CalculatorPopup(entry, CalculatorPopup.MODE_SUB) pixbuf_pixels = calc.render_icon(STOQ_CALC, Gtk.IconSize.MENU).get_pixels() self.assertEqual( entry.get_property('secondary-icon-pixbuf').get_pixels(), pixbuf_pixels) entry.set_sensitive(False) self.assertEqual(entry.get_property('secondary-icon-pixbuf'), None) entry.set_sensitive(True) self.assertEqual( entry.get_property('secondary-icon-pixbuf').get_pixels(), pixbuf_pixels) spinbutton = ProxySpinButton() spinbutton.data_type = currency self.assertEqual(spinbutton.get_property('secondary-icon-pixbuf'), None) calc = CalculatorPopup(spinbutton, CalculatorPopup.MODE_SUB) pixbuf_pixels = calc.render_icon(STOQ_CALC, Gtk.IconSize.MENU).get_pixels() self.assertEqual( spinbutton.get_property('secondary-icon-pixbuf').get_pixels(), pixbuf_pixels) spinbutton.set_sensitive(False) self.assertEqual(spinbutton.get_property('secondary-icon-pixbuf'), None) spinbutton.set_sensitive(True) self.assertEqual( spinbutton.get_property('secondary-icon-pixbuf').get_pixels(), pixbuf_pixels)
def _update_bank_type(self): self._remove_bank_option_widgets() bank_number = self.bank_type.get_selected() bank_info = None if bank_number: bank_info = get_bank_info_by_number(bank_number) self.bank_number = ProxyEntry() self.bank_number.props.data_type = int self.bank_number.set_sensitive(False) bank_number_lbl = self._add_widget(api.escape(_("Number:")), self.bank_number, options=True) self.bank_branch = ProxyEntry() self.bank_branch.connect('validate', self._on_bank_branch__validate, bank_info) self.bank_branch.props.data_type = 'str' self.bank_branch.props.mandatory = True self.bank_branch.model_attribute = "bank_branch" bank_branch_lbl = self._add_widget(api.escape(_("Agency:")), self.bank_branch, options=True) if bank_number is not None: bank_branch_lbl.show() self.bank_branch.show() else: bank_branch_lbl.hide() self.bank_account = ProxyEntry() self.bank_account.connect('validate', self._on_bank_account__validate, bank_info) self._add_widget(api.escape(_("Account:")), self.bank_account, options=True) self.bank_account.model_attribute = "bank_account" self.bank_account.props.data_type = 'str' if bank_number is not None: self.bank_account.props.mandatory = True self.bank_account.show() attributes = ['bank_account', 'bank_branch', 'bank_number'] if bank_number is not None: bank_number_lbl.show() self.bank_number.show() self.bank_model.bank_number = bank_number for i, option in enumerate(bank_info.get_extra_options()): name = 'option' + str(i) entry = ProxyEntry() entry.model_attribute = name setattr(self, name, entry) # Set the model attr too so it can be validated setattr(self.bank_model, name, u'') entry.props.data_type = 'str' entry.connect('validate', self._on_bank_option__validate, bank_info, option) name = option.replace('_', ' ').capitalize() self._add_widget("<i>%s</i>:" % api.escape(name), entry, options=True) entry.show() self._option_fields[option] = entry attributes.append(entry.model_attribute) else: bank_number_lbl.hide() self.bank_proxy = self.add_proxy(self.bank_model, attributes) self._fill_bank_account()
def build_widget(self): entry = ProxyEntry() return entry
def build_widget(self): widget = ProxyEntry() return widget
def __init__(self): entry = ProxyEntry() ComboEntry.__init__(self, entry=entry) ValidatableProxyWidgetMixin.__init__(self) entry.connect('content-changed', self._on_entry__content_changed) entry.connect('validation-changed', self._on_entry__validation_changed)