コード例 #1
0
ファイル: accounteditor.py プロジェクト: ComradeHadi/stoq
    def _update_account_type(self, account_type):
        if not self.account_type.get_sensitive():
            return
        if account_type != Account.TYPE_BANK:
            self._remove_bank_widgets()
            self._remove_bank_option_widgets()
            self.code.set_sensitive(True)
            return

        self.code.set_sensitive(False)
        self.bank_type = ProxyComboBox()
        self._add_widget(api.escape(_("Bank:")), self.bank_type)
        self.bank_type.connect('content-changed',
                               self._on_bank_type__content_changed)
        self.bank_type.show()

        banks = [(_('Generic'), None)]
        banks.extend([(b.description, b.bank_number) for b in get_all_banks()])
        self.bank_type.prefill(banks)

        if self.model.bank:
            try:
                self.bank_type.select(self.model.bank.bank_number)
            except KeyError:
                self.bank_type.select(None)

        self._update_bank_type()
コード例 #2
0
    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        # We create the mode, but it will only be added to this box when
        # enable_advanced is called
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        for option in (ComboEquals, ComboDifferent):
            self.add_option(option)
        self.mode.select_item_by_position(0)

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()
コード例 #3
0
    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = Gtk.Label(label=label)
        self.pack_start(label, False, False, 0)
        label.show()
        self.title_label = label

        # We create the mode, but it will only be added to this box when
        # enable_advanced is called
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        for option in (ComboEquals, ComboDifferent):
            self.add_option(option)
        self.mode.select_item_by_position(0)

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()
コード例 #4
0
 def add_combo(self, data=None):
     """Add a combo for selecting an option"""
     combo = ProxyComboBox()
     self.pack_start(combo, False, False, 0)
     if data:
         combo.prefill(data)
     return combo
コード例 #5
0
ファイル: search.py プロジェクト: hsavolai/vmlab
    def __init__(self, label, chars=0):
        """
        Create a new StringSearchFilter object.
        @param label: label of the search filter
        @param chars: maximum number of chars used by the search entry
        """
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = gtk.Entry()
        self.entry.connect('activate', self._on_entry__activate)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in (Contains, DoesNotContain):
            self._add_option(option)
        self.mode.select_item_by_position(0)
コード例 #6
0
    def _setup_work_orders_widgets(self):
        self._work_orders_hbox = Gtk.HBox(spacing=6)
        self.item_vbox.pack_start(self._work_orders_hbox, False, True, 6)
        self.item_vbox.reorder_child(self._work_orders_hbox, 0)
        self._work_orders_hbox.show()

        label = Gtk.Label(label=_("Work order:"))
        self._work_orders_hbox.pack_start(label, False, True, 0)

        data = []
        for wo in self.wizard.workorders:
            # The work order might be already approved if we are editing a sale
            if wo.can_approve():
                wo.approve()

            self.setup_work_order(wo)
            data.append([wo.description, wo])

        if len(data) <= _MAX_WORK_ORDERS_FOR_RADIO:
            self.work_orders_combo = None
            for desc, wo in data:
                self._add_work_order_radio(desc, wo)
        else:
            self.work_orders_combo = ProxyComboBox()
            self.work_orders_combo.prefill(data)
            self._selected_workorder = self.work_orders_combo.get_selected()
            self._work_orders_hbox.pack_start(self.work_orders_combo, False,
                                              False, 0)

        self._work_orders_hbox.show_all()
コード例 #7
0
 def add_combo(self, data=None):
     """Add a combo for selecting an option"""
     combo = ProxyComboBox()
     self.pack_start(combo, False, False, 0)
     if data:
         combo.prefill(data)
     return combo
コード例 #8
0
ファイル: productslave.py プロジェクト: amaurihamasu/stoq
    def _add_options(self, attr, pos):
        combo = ProxyComboBox()
        label = gtk.Label(attr.attribute.description)

        # This dictionary is populated with the purpose of tests
        self._widgets[attr.attribute.description] = combo
        self.attr_table.attach(label, 0, 1, pos, pos + 1, 0, 0, 0, 0)
        self.attr_table.attach(combo, 1, 2, pos, pos + 1, 0, gtk.EXPAND | gtk.FILL, 0, 0)
        self.attr_table.show_all()
        self._fill_options(combo, attr)
        combo.connect('changed', self._on_combo_selection__changed)
コード例 #9
0
ファイル: productslave.py プロジェクト: leandrodax/stoq
    def _add_options(self, attr, pos):
        combo = ProxyComboBox()
        label = gtk.Label(attr.attribute.description)

        # This dictionary is populated with the purpose of tests
        self._widgets[attr.attribute.description] = combo
        self.attr_table.attach(label, 0, 1, pos, pos + 1, 0, 0, 0, 0)
        self.attr_table.attach(combo, 1, 2, pos, pos + 1, 0, gtk.EXPAND | gtk.FILL, 0, 0)
        self.attr_table.show_all()
        self._fill_options(combo, attr)
        combo.connect('changed', self._on_combo_selection__changed)
コード例 #10
0
ファイル: search.py プロジェクト: dsaran/packagehelper
class ComboSearchFilter(SearchFilter):
    """
    - a label
    - a combo with a set of predefined item to select from
    """
    __gtype_name__ = 'ComboSearchFilter'

    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        @param name: name of the search filter
        @param values: items to put in the combo, see
            L{kiwi.ui.widgets.combo.ProxyComboBox.prefill}
        """
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        self.combo = ProxyComboBox()
        if values:
            self.combo.prefill(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()

    #
    # SearchFilter
    #

    def get_state(self):
        return NumberQueryState(filter=self,
                                value=self.combo.get_selected_data())

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.combo

    #
    # Public API
    #

    def select(self, data):
        """
        selects an item in the combo
        @param data: what to select
        """
        self.combo.select(data)

    #
    # Callbacks
    #

    def _on_combo__content_changed(self, mode):
        self.emit('changed')
コード例 #11
0
ファイル: test_ComboBox.py プロジェクト: hackedbellini/kiwi
    def test_prefill_attr_none(self):
        model = Settable(attr=None)
        proxy = Proxy(FakeView(), model)
        combo = ProxyComboBox()
        combo.data_type = int
        combo.model_attribute = 'attr'
        combo.prefill([('foo', 10), ('bar', 20)])
        proxy.add_widget('attr', combo)

        # Even though attr is None, the combo doesn't allow something
        # not prefilled in it to be selected. In this case, it will select
        # the first item (prefill actually does that) instead.
        self.assertEqual(model.attr, 10)
コード例 #12
0
 def build_widget(self):
     if self.use_entry:
         combo = ProxyComboEntry()
     else:
         combo = ProxyComboBox()
     self.fill(combo)
     return combo
コード例 #13
0
ファイル: workorderquotewizard.py プロジェクト: pkaislan/stoq
    def _setup_work_orders_widgets(self):
        self._work_orders_hbox = gtk.HBox(spacing=6)
        self.item_vbox.pack_start(self._work_orders_hbox, False, True, 6)
        self.item_vbox.reorder_child(self._work_orders_hbox, 0)
        self._work_orders_hbox.show()

        label = gtk.Label(_("Work order:"))
        self._work_orders_hbox.pack_start(label, False, True)

        data = []
        for wo in self.wizard.workorders:
            # The work order might be already approved if we are editing a sale
            if wo.can_approve():
                wo.approve()

            self.setup_work_order(wo)
            data.append([wo.description, wo])

        if len(data) <= _MAX_WORK_ORDERS_FOR_RADIO:
            self.work_orders_combo = None
            for desc, wo in data:
                self._add_work_order_radio(desc, wo)
        else:
            self.work_orders_combo = ProxyComboBox()
            self.work_orders_combo.prefill(data)
            self._selected_workorder = self.work_orders_combo.get_selected()
            self._work_orders_hbox.pack_start(self.work_orders_combo,
                                              False, False)

        self._work_orders_hbox.show_all()
コード例 #14
0
ファイル: accounteditor.py プロジェクト: romaia/stoq
    def _update_account_type(self, account_type):
        if not self.account_type.get_sensitive():
            return
        if account_type != Account.TYPE_BANK:
            self._remove_bank_widgets()
            self._remove_bank_option_widgets()
            self.code.set_sensitive(True)
            return

        self.code.set_sensitive(False)
        self.bank_type = ProxyComboBox()
        self._add_widget(api.escape(_("Bank:")), self.bank_type)
        self.bank_type.connect('content-changed',
                               self._on_bank_type__content_changed)
        self.bank_type.show()

        banks = [(_('Generic'), None)]
        banks.extend([(b.description,
                       b.bank_number) for b in get_all_banks()])
        self.bank_type.prefill(banks)

        if self.model.bank:
            try:
                self.bank_type.select(self.model.bank.bank_number)
            except KeyError:
                self.bank_type.select(None)

        self._update_bank_type()
コード例 #15
0
ファイル: chartdialog.py プロジェクト: leandrorchaves/stoq
    def __init__(self):
        self._js_data = None
        self._js_options = None
        self._current = None

        gtk.Window.__init__(self)
        self.set_size_request(800, 480)

        self.vbox = gtk.VBox()
        self.add(self.vbox)
        self.vbox.show()

        hbox = gtk.HBox()
        self.vbox.pack_start(hbox, False, False, 6)
        hbox.show()

        label = gtk.Label('Period:')
        hbox.pack_start(label, False, False, 6)
        label.show()

        self.chart_type = ProxyComboBox()
        self.chart_type.connect(
            'content-changed',
            self._on_chart_type__content_changed)
        hbox.pack_start(self.chart_type, False, False, 6)
        self.chart_type.show()

        self.period_values = ProxyComboBox()
        self.period_values.connect(
            'content-changed',
            self._on_period_values__content_changed)
        hbox.pack_start(self.period_values, False, False, 6)
        self.period_values.show()

        self._view = WebView()
        self._view.get_view().connect(
            'load-finished',
            self._on_view__document_load_finished)
        self.vbox.pack_start(self._view, True, True)

        self.results = ObjectList()
        self.results.connect(
            'row-activated',
            self._on_results__row_activated)
        self.vbox.pack_start(self.results, True, True)

        self._setup_daemon()
コード例 #16
0
    def _setup_widgets(self):
        self.pack_start(gtk.Label(_('Update')), False, False)
        self.field_combo = ProxyComboBox()
        self.field_combo.connect('changed', self._on_field_combo__changed)
        self.pack_start(self.field_combo, False, False)
        self.editor_placeholder = gtk.EventBox()
        self.pack_start(self.editor_placeholder, False, False)
        self.apply_button = gtk.Button(stock=gtk.STOCK_APPLY)
        self.apply_button.connect('clicked', self._on_apply_button__clicked)
        self.pack_start(self.apply_button, False, False)

        for field in self._fields:
            # Don't let the user edit unique fields for now
            if field.unique:
                continue
            self.field_combo.append_item(field.label, field)
        self.field_combo.select_item_by_position(0)
コード例 #17
0
ファイル: productslave.py プロジェクト: 5l1v3r1/stoq-1
    def _add_options(self, attr, pos):
        combo = ProxyComboBox()
        label = Gtk.Label(label=attr.attribute.description + u':')
        label.set_alignment(xalign=1, yalign=0.5)

        # This dictionary is populated with the purpose of tests
        self._widgets[attr.attribute.description] = combo
        # Use 3 labels per row
        row_pos = pos / 3
        col_pos = 2 * (pos % 3)
        self.attr_table.attach(label, col_pos, col_pos + 1, row_pos, row_pos + 1,
                               Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0)
        self.attr_table.attach(combo, col_pos + 1, col_pos + 2, row_pos, row_pos + 1,
                               Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0)
        self.attr_table.show_all()
        self._fill_options(combo, attr)
        combo.connect('changed', self._on_combo_selection__changed)
コード例 #18
0
ファイル: search.py プロジェクト: hsavolai/vmlab
    def __init__(self, label=''):
        """
        Create a new DateSearchFilter object.
        @param label: name of the search filter
        """
        self._options = {}
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect(
            'content-changed',
            self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.from_label = gtk.Label(_("From:"))
        self.pack_start(self.from_label, False, False)
        self.from_label.show()

        self.start_date = ProxyDateEntry()
        self._start_changed_id = self.start_date.connect(
            'content-changed', self._on_start_date__changed)
        self.pack_start(self.start_date, False, False, 6)
        self.start_date.show()

        self.to_label = gtk.Label(_("To:"))
        self.pack_start(self.to_label, False, False)
        self.to_label.show()

        self.end_date = ProxyDateEntry()
        self._end_changed_id = self.end_date.connect(
            'content-changed', self._on_end_date__changed)
        self.pack_start(self.end_date, False, False, 6)
        self.end_date.show()

        self.add_custom_options()

        for option in (Any, Today, Yesterday, LastWeek, LastMonth):
            self.add_option(option)

        self.mode.select_item_by_position(0)
コード例 #19
0
    def __init__(self, label=''):
        """
        Create a new NumberSearchFilter object.
        :param label: name of the search filter
        """

        self._options = {}

        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.title_label.set_alignment(1.0, 0.5)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.start = Gtk.SpinButton(climb_rate=1.0)
        self.start.set_adjustment(
            Gtk.Adjustment(lower=-MAX_INT - 1, upper=MAX_INT,
                           step_increment=1))
        self.pack_start(self.start, False, False, 6)
        self.start.show()
        self.start.connect_after('activate', self._on_entry__activate)

        self.and_label = Gtk.Label(label=_("And"))
        self.pack_start(self.and_label, False, False, 0)
        self.and_label.show()

        self.end = Gtk.SpinButton(climb_rate=1.0)
        self.start.set_adjustment(
            Gtk.Adjustment(lower=-MAX_INT - 1, upper=MAX_INT,
                           step_increment=1))
        self.pack_start(self.end, False, False, 6)
        self.end.show()
        self.end.connect_after('activate', self._on_entry__activate)

        for option in (LowerThan, EqualsTo, GreaterThan, Between):
            self.add_option(option)

        self.mode.select_item_by_position(0)
コード例 #20
0
    def _setup_options_combo_slave(self):
        widget = ProxyComboBox()
        widget.props.sensitive = self.sensitive
        widget.model_attribute = "field_value"
        widget.data_type = unicode

        data = [(value, unicode(key))
                for key, value in self.detail.options.items()]
        widget.prefill(data)
        self.proxy.add_widget("field_value", widget)
        self.container.add(widget)
        widget.show()
コード例 #21
0
ファイル: search.py プロジェクト: hsavolai/vmlab
    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        @param name: name of the search filter
        @param values: items to put in the combo, see
            L{kiwi.ui.widgets.combo.ProxyComboBox.prefill}
        """
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        self.combo = ProxyComboBox()
        if values:
            self.combo.prefill(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()
コード例 #22
0
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = Gtk.Entry()
        self.entry.set_placeholder_text(_("Search"))
        self.entry.props.secondary_icon_sensitive = False
        data = environ.get_resource_string('stoq', 'pixmaps',
                                           'stoq-funnel-16x16.png')
        image = pixbuf_from_string(data)
        self.entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, image)
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY,
                                         _("Add a filter"))
        self.entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY,
                                       Gtk.STOCK_CLEAR)
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in [
                ContainsAll, ContainsExactly, IdenticalTo, DoesNotContain
        ]:
            self._add_option(option)
        self.mode.select_item_by_position(0)
コード例 #23
0
    def __init__(self):
        self._js_data = None
        self._js_options = None
        self._current = None

        gtk.Window.__init__(self)
        self.set_size_request(800, 480)

        self.vbox = gtk.VBox()
        self.add(self.vbox)
        self.vbox.show()

        hbox = gtk.HBox()
        self.vbox.pack_start(hbox, False, False, 6)
        hbox.show()

        label = gtk.Label('Period:')
        hbox.pack_start(label, False, False, 6)
        label.show()

        self.chart_type = ProxyComboBox()
        self.chart_type.connect('content-changed',
                                self._on_chart_type__content_changed)
        hbox.pack_start(self.chart_type, False, False, 6)
        self.chart_type.show()

        self.period_values = ProxyComboBox()
        self.period_values.connect('content-changed',
                                   self._on_period_values__content_changed)
        hbox.pack_start(self.period_values, False, False, 6)
        self.period_values.show()

        self._view = WebView()
        self._view.get_view().connect('load-finished',
                                      self._on_view__document_load_finished)
        self.vbox.pack_start(self._view, True, True)

        self.results = ObjectList()
        self.results.connect('row-activated', self._on_results__row_activated)
        self.vbox.pack_start(self.results, True, True)

        self._setup_daemon()
コード例 #24
0
    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()
コード例 #25
0
    def __init__(self, store, field, other_fields):
        """
        :param store: a storm store if its needed
        :param field: the field that is being edited
        :param other_fields: other fields available for math operations
        """
        assert len(self.operations)

        self._store = store
        self._other_fields = other_fields
        self._oper = None
        self._field = field
        super(Editor, self).__init__(spacing=6)
        self.operations_combo = ProxyComboBox()
        self.pack_start(self.operations_combo, True, True, 0)
        self.operations_combo.connect('changed', self._on_operation_changed)
        for oper in self.operations:
            self.operations_combo.append_item(oper.label, oper)
        self.operations_combo.select(self.operations[0])
        self.show_all()
コード例 #26
0
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = Gtk.Entry()
        self.entry.set_placeholder_text(_("Search"))
        self.entry.props.secondary_icon_sensitive = False
        self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY,
                                           'fa-filter-symbolic')
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY,
                                         _("Add a filter"))
        self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY,
                                           'edit-clear-symbolic')
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        # Default filter will be only contains all. When advanced filter is enabled it will add
        # other options
        self._add_option(ContainsAll)
        self.mode.select_item_by_position(0)
コード例 #27
0
ファイル: parameterseditor.py プロジェクト: coletivoEITA/stoq
    def _setup_options_combo_slave(self):
        widget = ProxyComboBox()
        widget.props.sensitive = self.sensitive
        widget.model_attribute = "field_value"
        widget.data_type = unicode

        data = [(value, unicode(key)) for key, value in self.detail.options.items()]
        widget.prefill(data)
        self.proxy.add_widget("field_value", widget)
        self.container.add(widget)
        widget.show()
コード例 #28
0
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = HintedEntry()
        self.entry.set_hint(_("Search"))
        self.entry.show_hint()
        self.entry.props.secondary_icon_sensitive = False
        self.entry.set_icon_from_stock(gtk.ENTRY_ICON_PRIMARY, gtk.STOCK_FIND)
        self.entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY,
                                       gtk.STOCK_CLEAR)
        self.entry.set_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in (ContainsAll, ContainsExactly, DoesNotContain):
            self._add_option(option)
        self.mode.select_item_by_position(0)
コード例 #29
0
    def _setup_widgets(self):
        self.pack_start(gtk.Label(_('Update')), False, False)
        self.field_combo = ProxyComboBox()
        self.field_combo.connect('changed', self._on_field_combo__changed)
        self.pack_start(self.field_combo, False, False)
        self.editor_placeholder = gtk.EventBox()
        self.pack_start(self.editor_placeholder, False, False)
        self.apply_button = gtk.Button(stock=gtk.STOCK_APPLY)
        self.apply_button.connect('clicked', self._on_apply_button__clicked)
        self.pack_start(self.apply_button, False, False)

        for field in self._fields:
            # Don't let the user edit unique fields for now
            if field.unique:
                continue
            self.field_combo.append_item(field.label, field)
        self.field_combo.select_item_by_position(0)
コード例 #30
0
ファイル: test_ComboBox.py プロジェクト: rosemberg-al/kiwi
    def test_prefill_attr_none(self):
        model = Settable(attr=None)
        proxy = Proxy(FakeView(), model)
        combo = ProxyComboBox()
        combo.data_type = int
        combo.model_attribute = 'attr'
        combo.prefill([('foo', 10), ('bar', 20)])
        proxy.add_widget('attr', combo)

        # Even though attr is None, the combo doesn't allow something
        # not prefilled in it to be selected. In this case, it will select
        # the first item (prefill actually does that) instead.
        self.assertEqual(model.attr, 10)
コード例 #31
0
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = HintedEntry()
        self.entry.set_hint(_("Search"))
        self.entry.show_hint()
        self.entry.props.secondary_icon_sensitive = False
        data = environ.get_resource_string('stoq', 'pixmaps',
                                           'stoq-funnel-16x16.png')
        image = pixbuf_from_string(data)
        self.entry.set_icon_from_pixbuf(gtk.ENTRY_ICON_PRIMARY,
                                        image)
        self.entry.set_icon_tooltip_text(gtk.ENTRY_ICON_PRIMARY,
                                         _("Add a filter"))
        self.entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY,
                                       gtk.STOCK_CLEAR)
        self.entry.set_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in (ContainsAll, ContainsExactly, DoesNotContain):
            self._add_option(option)
        self.mode.select_item_by_position(0)
コード例 #32
0
    def __init__(self, store, field, other_fields):
        """
        :param store: a storm store if its needed
        :param field: the field that is being edited
        :param other_fields: other fields available for math operations
        """
        assert len(self.operations)

        self._store = store
        self._other_fields = other_fields
        self._oper = None
        self._field = field
        super(Editor, self).__init__(spacing=6)
        self.operations_combo = ProxyComboBox()
        self.pack_start(self.operations_combo, True, True, 0)
        self.operations_combo.connect('changed', self._on_operation_changed)
        for oper in self.operations:
            self.operations_combo.append_item(oper.label, oper)
        self.operations_combo.select(self.operations[0])
        self.show_all()
コード例 #33
0
ファイル: searchfilters.py プロジェクト: LeonamSilva/stoq
    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()
コード例 #34
0
ファイル: search.py プロジェクト: hsavolai/vmlab
    def __init__(self, label=''):
        """
        Create a new NumberSearchFilter object.
        @param label: name of the search filter
        """

        self._options = {}

        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.title_label.set_alignment(1.0, 0.5)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.start = gtk.SpinButton(climb_rate=1.0)
        self.start.get_adjustment().step_increment = 1.0
        self.start.set_range(-sys.maxint-1, sys.maxint)
        self.pack_start(self.start, False, False, 6)
        self.start.show()
        self.start.connect_after('activate', self._on_entry__activate)

        self.and_label = gtk.Label(_("And"))
        self.pack_start(self.and_label, False, False)
        self.and_label.show()

        self.end = gtk.SpinButton(climb_rate=1.0)
        self.end.get_adjustment().step_increment = 1.0
        self.end.set_range(-sys.maxint-1, sys.maxint)
        self.pack_start(self.end, False, False, 6)
        self.end.show()
        self.end.connect_after('activate', self._on_entry__activate)

        for option in (LowerThan, EqualsTo, GreaterThan, Between):
            self.add_option(option)

        self.mode.select_item_by_position(0)
コード例 #35
0
ファイル: searchfilters.py プロジェクト: hackedbellini/stoq
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = Gtk.Entry()
        self.entry.set_placeholder_text(_("Search"))
        self.entry.props.secondary_icon_sensitive = False
        self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY,
                                           'fa-filter-symbolic')
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY,
                                         _("Add a filter"))
        self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY,
                                           'edit-clear-symbolic')
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        # Default filter will be only contains all. When advanced filter is enabled it will add
        # other options
        self._add_option(ContainsAll)
        self.mode.select_item_by_position(0)
コード例 #36
0
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
コード例 #37
0
class Editor(Gtk.HBox):
    """Base class for field editors

    Subclasses must define a list of operations and a datatype
    """

    operations = []
    data_type = None

    def __init__(self, store, field, other_fields):
        """
        :param store: a storm store if its needed
        :param field: the field that is being edited
        :param other_fields: other fields available for math operations
        """
        assert len(self.operations)

        self._store = store
        self._other_fields = other_fields
        self._oper = None
        self._field = field
        super(Editor, self).__init__(spacing=6)
        self.operations_combo = ProxyComboBox()
        self.pack_start(self.operations_combo, True, True, 0)
        self.operations_combo.connect('changed', self._on_operation_changed)
        for oper in self.operations:
            self.operations_combo.append_item(oper.label, oper)
        self.operations_combo.select(self.operations[0])
        self.show_all()

    def set_field(self, field):
        assert field.data_type == self.data_type
        self._field = field
        self._oper.set_field(field)

    def _on_operation_changed(self, combo):
        if self._oper is not None:
            # Remove previous operation
            self.remove(self._oper)

        self._oper = combo.get_selected()(self._store, self._field,
                                          self._other_fields)
        self.pack_start(self._oper, True, True, 0)

    def apply_operation(self, item):
        return self._oper.apply_operation(item)
コード例 #38
0
class Editor(Gtk.HBox):
    """Base class for field editors

    Subclasses must define a list of operations and a datatype
    """

    operations = []
    data_type = None

    def __init__(self, store, field, other_fields):
        """
        :param store: a storm store if its needed
        :param field: the field that is being edited
        :param other_fields: other fields available for math operations
        """
        assert len(self.operations)

        self._store = store
        self._other_fields = other_fields
        self._oper = None
        self._field = field
        super(Editor, self).__init__(spacing=6)
        self.operations_combo = ProxyComboBox()
        self.pack_start(self.operations_combo, True, True, 0)
        self.operations_combo.connect('changed', self._on_operation_changed)
        for oper in self.operations:
            self.operations_combo.append_item(oper.label, oper)
        self.operations_combo.select(self.operations[0])
        self.show_all()

    def set_field(self, field):
        assert field.data_type == self.data_type
        self._field = field
        self._oper.set_field(field)

    def _on_operation_changed(self, combo):
        if self._oper is not None:
            # Remove previous operation
            self.remove(self._oper)

        self._oper = combo.get_selected()(self._store, self._field,
                                          self._other_fields)
        self.pack_start(self._oper, True, True, 0)

    def apply_operation(self, item):
        return self._oper.apply_operation(item)
コード例 #39
0
class StringSearchFilter(SearchFilter):
    """
    Contains:

      - a label
      - an entry

    :ivar entry: the entry
    :ivar label: the label
    """

    __gtype_name__ = 'StringSearchFilter'

    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = Gtk.Entry()
        self.entry.set_placeholder_text(_("Search"))
        self.entry.props.secondary_icon_sensitive = False
        data = environ.get_resource_string('stoq', 'pixmaps',
                                           'stoq-funnel-16x16.png')
        image = pixbuf_from_string(data)
        self.entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, image)
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY,
                                         _("Add a filter"))
        self.entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY,
                                       Gtk.STOCK_CLEAR)
        self.entry.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in [
                ContainsAll, ContainsExactly, IdenticalTo, DoesNotContain
        ]:
            self._add_option(option)
        self.mode.select_item_by_position(0)

    def _add_option(self, option_type):
        option = option_type()
        self.mode.append_item(option.name, option_type)
        self._options[option_type] = option

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, combo):
        self.emit('changed')

    def _on_entry__activate(self, entry):
        self.emit('changed')

    def _on_entry__changed(self, entry):
        entry.props.secondary_icon_sensitive = bool(entry.get_text())

    def _position_filter_menu(self, data):
        window = self.entry.get_icon_window(Gtk.EntryIconPosition.PRIMARY)
        x, y = window.get_origin()
        y += window.get_size()[1]
        border = self.entry.style_get_property('progress-border')
        if border is not None:
            y += border.bottom
        return (x, y, True)

    def _on_entry__icon_release(self, entry, icon_pos, event):
        if icon_pos == Gtk.EntryIconPosition.SECONDARY:
            entry.set_text("")
            entry.grab_focus()
            self.emit('changed')
        elif icon_pos == Gtk.EntryIconPosition.PRIMARY:
            # We don't need create popup filters if haven't search columns.
            if (not self._container or not hasattr(self._container, 'menu')
                    or not self._container.menu):
                return
            self._container.menu.popup(None, None, None,
                                       self._position_filter_menu, 0,
                                       event.time)

    #
    # SearchFilter
    #

    def get_state(self):
        option = self.mode.get_selected_data()
        return StringQueryState(filter=self,
                                text=str(self.entry.get_text()),
                                mode=option and option.mode)

    def set_state(self, text, mode=None):
        self.entry.set_text(text)
        if mode is not None:
            self.mode.select_item_by_position(mode)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = self.entry.get_text()
        if desc:
            mode = self.mode.get_selected_label()
            return '%s %s "%s"' % (
                self.title_label.get_text(),
                mode,
                desc,
            )

    #
    # Public API
    #

    def enable_advanced(self):
        # Do not show the funnel icon if its an advanced filter
        self.entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, None)
        self.mode.show()

    def set_label(self, label):
        self.title_label.set_text(label)
コード例 #40
0
ファイル: search.py プロジェクト: hsavolai/vmlab
class DateSearchFilter(SearchFilter):
    """
    A filter which helps you to search by a date interval.
    Can be customized through add_option.
    """
    __gtype_name__ = 'DateSearchFilter'
    class Type(enum):
        (USER_DAY,
         USER_INTERVAL) = range(100, 102)

    def __init__(self, label=''):
        """
        Create a new DateSearchFilter object.
        @param label: name of the search filter
        """
        self._options = {}
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect(
            'content-changed',
            self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.from_label = gtk.Label(_("From:"))
        self.pack_start(self.from_label, False, False)
        self.from_label.show()

        self.start_date = ProxyDateEntry()
        self._start_changed_id = self.start_date.connect(
            'content-changed', self._on_start_date__changed)
        self.pack_start(self.start_date, False, False, 6)
        self.start_date.show()

        self.to_label = gtk.Label(_("To:"))
        self.pack_start(self.to_label, False, False)
        self.to_label.show()

        self.end_date = ProxyDateEntry()
        self._end_changed_id = self.end_date.connect(
            'content-changed', self._on_end_date__changed)
        self.pack_start(self.end_date, False, False, 6)
        self.end_date.show()

        self.add_custom_options()

        for option in (Any, Today, Yesterday, LastWeek, LastMonth):
            self.add_option(option)

        self.mode.select_item_by_position(0)

    #
    # SearchFilter
    #

    def get_state(self):
        start = self.start_date.get_date()
        end = self.end_date.get_date()
        if start == end:
            return DateQueryState(filter=self, date=start)
        return DateIntervalQueryState(filter=self, start=start, end=end)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = ''
        start_date = self.start_date.get_date()
        end_date = self.end_date.get_date()
        if start_date:
            if end_date and start_date != end_date:
                desc += ' %s %s %s %s' % (_(u'from'), start_date.strftime('%x'),
                                          _(u'to'), end_date.strftime('%x'),)

            else:
                 desc += start_date.strftime('%x')
        if desc:
            return '%s %s' % (self.get_title_label().get_text(), desc,)

    #
    # Public API
    #

    def clear_options(self):
        """
        Removes all previously added options
        """
        self._options = {}
        self.mode.clear()

    def add_option(self, option_type, position=-2):
        """
        Adds a date option
        @param option_type: option to add
        @type option_type: a L{DateSearchOption} subclass
        """
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option

    def add_option_fixed(self, name, date, position=-2):
        """
        Adds a fixed option, eg one for which date is not
        possible to modify.
        @param name: name of the option
        @param date: fixed data
        @param position: position to add the option at
        """
        option_type = type('', (FixedDateSearchOption,),
                           dict(name=name, date=date))
        self.add_option(option_type, position=position)


    def add_option_fixed_interval(self, name, start, end, position=-2):
        """
        Adds a fixed option interval, eg one for which the dates are not
        possible to modify.
        @param name: name of the option
        @param start: start of the fixed interval
        @param end: end of the fixed interval
        @param position: position to add the option at
        """
        option_type = type('', (FixedIntervalSearchOption,),
                           dict(name=name, start=start, end=end))
        self.add_option(option_type, position=position)

    def add_custom_options(self):
        """Adds the custom options 'Custom day' and 'Custom interval' which
        let the user define its own interval dates.
        """
        pos = len(self.mode) + 1
        for name, option_type in [
            (_('Custom day'), DateSearchFilter.Type.USER_DAY),
            (_('Custom interval'), DateSearchFilter.Type.USER_INTERVAL)]:

            self.mode.insert_item(pos, name, option_type)
            pos += 1

    def get_start_date(self):
        """
        Get the start date.
        @returns: start date
        @rtype: datetime.date or None
        """
        return self.start_date.get_date()

    def get_end_date(self):
        """
        Get the end date.
        @returns: end date
        @rtype: datetime.date or None
        """
        return self.end_date.get_date()

    def set_use_date_entries(self, use_date_entries):
        """
        Toggles the visibility of the user selectable date entries
        @param use_date_entries:
        """
        self.from_label.props.visible = use_date_entries
        self.to_label.props.visible = use_date_entries
        self.start_date.props.visible = use_date_entries
        self.end_date.props.visible = use_date_entries

    def select(self, data=None, position=None):
        """
        selects an item in the combo
        Data or position can be sent in. If nothing
        is sent in the first item will be selected, if any

        @param data: data to select
        @param position: position of data to select
        """
        if data is not None and position is not None:
            raise TypeError("You can't send in both data and position")

        if data is None and position is None:
            position = 0

        if position is not None:
            if len(self.mode):
                self.mode.select_item_by_position(position)
        elif data:
            self.mode.select(data)

    #
    # Private
    #

    def _update_dates(self):
        # This is called when we change mode
        date_type = self.mode.get_selected_data()
        if date_type is None:
            return

        # If we switch to a user selectable day, make sure that
        # both dates are set to today
        if date_type == DateSearchFilter.Type.USER_DAY:
            today = datetime.date.today()
            self.start_date.set_date(today)
            self.end_date.set_date(today)
        # And for user interval, set start to today and to tomorrow
        elif date_type == DateSearchFilter.Type.USER_INTERVAL:
            today = datetime.date.today()
            self.start_date.set_date(today)
            self.end_date.set_date(today + datetime.timedelta(days=1))
        # Finally for pre-defined ones let the DateSearchOption decide what the
        # values are going to be, these dates are not user editable so
        # we don't need to do any checking.
        else:
            option = self._options.get(date_type)
            assert option, (date_type, self._options)
            start_date, end_date = option.get_interval()
            self.start_date.set_date(start_date)
            self.end_date.set_date(end_date)

    def _update_sensitivity(self):
        date_type = self.mode.get_selected_data()
        enabled = date_type == DateSearchFilter.Type.USER_INTERVAL
        self.to_label.set_sensitive(enabled)
        self.end_date.set_sensitive(enabled)

        enabled = (date_type == DateSearchFilter.Type.USER_INTERVAL or
                   date_type == DateSearchFilter.Type.USER_DAY)
        self.from_label.set_sensitive(enabled)
        self.start_date.set_sensitive(enabled)

    def _internal_set_start_date(self, date):
        self.start_date.handler_block(self._start_changed_id)
        self.start_date.set_date(date)
        self.start_date.handler_unblock(self._start_changed_id)

    def _internal_set_end_date(self, date):
        self.end_date.handler_block(self._end_changed_id)
        self.end_date.set_date(date)
        self.end_date.handler_unblock(self._end_changed_id)

    def _restore_date_validation(self):
        self.start_date.set_valid()
        self.end_date.set_valid()

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, mode):
        self._update_dates()
        self._update_sensitivity()
        self._restore_date_validation()
        self.emit('changed')

    def _on_start_date__changed(self, start_date):
        date_type = self.mode.get_selected_data()
        start = start_date.get_date()
        # For user days, just make sure that the date entries
        # always are in sync
        if date_type == DateSearchFilter.Type.USER_DAY:
            if start is None:
                self.start_date.set_invalid(_(u'Invalid date'))
            else:
                self.start_date.set_valid()
                self._internal_set_end_date(start)
        # Make sure that we cannot select a start date after
        # the end date, be nice and increase the end date if
        # the start date happen to be the same
        elif date_type == DateSearchFilter.Type.USER_INTERVAL:
            end = self.end_date.get_date()
            if start is None:
                self.start_date.set_invalid(_(u'Invalid date'))
                return
            if end and start >= end:
                self._internal_set_end_date(start + datetime.timedelta(days=1))

            self.start_date.set_valid()

    def _on_end_date__changed(self, end_date):
        date_type = self.mode.get_selected_data()
        # We don't need to do anything for user day, since
        # this the end date widget is disabled
        if date_type == DateSearchFilter.Type.USER_DAY:
            pass
        # Make sure that we cannot select an end date before
        # the start date, be nice and decrease the start date if
        # the end date happen to be the same
        elif date_type == DateSearchFilter.Type.USER_INTERVAL:
            start = self.start_date.get_date()
            end = end_date.get_date()
            if end is None:
                self.end_date.set_invalid(_(u'Invalid date'))
            else:
                self.end_date.set_valid()

            if start and end and end <= start:
                self._internal_set_start_date(end - datetime.timedelta(days=1))
コード例 #41
0
class ComboSearchFilter(SearchFilter):
    """
    - a label
    - a combo with a set of predefined item to select from
    """
    __gtype_name__ = 'ComboSearchFilter'

    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = Gtk.Label(label=label)
        self.pack_start(label, False, False, 0)
        label.show()
        self.title_label = label

        # We create the mode, but it will only be added to this box when
        # enable_advanced is called
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        for option in (ComboEquals, ComboDifferent):
            self.add_option(option)
        self.mode.select_item_by_position(0)

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()

    #
    # SearchFilter
    #

    def get_state(self):
        value = self.combo.get_selected_data()
        mode = self.mode.get_selected_data()
        state = NumberQueryState(filter=self, value=value, mode=mode.mode)
        if hasattr(value, 'id'):
            state.value_id = value.id
        return state

    def set_state(self, value, value_id=None, mode=None):
        if mode is None:
            mode = NumberQueryState.EQUALS
        if value_id is not None:
            for item in self.combo.get_model_items().values():
                if item is None:
                    continue
                # Filter can come as a string or as a FilterItem object
                item_id = item if isinstance(item, str) else item.id
                if item_id == value_id:
                    value = item
                    break
        self.select(value)

    def update_values(self, values):
        self._block_updates = True
        self.combo.prefill(values)
        self._block_updates = False

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.combo

    def get_description(self):
        desc = ''
        data = self.combo.get_selected_data()
        if data is not None:
            desc += self.combo.get_selected_label()
            return '%s %s' % (
                self.title_label.get_text(),
                desc,
            )

    #
    # Public API
    #

    def add_option(self, option_type, position=0):
        """
        Adds an option
        :param option_type: option to add
        :type option_type: a :class:`ComboSearchOption` subclass
        """
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)

    def select(self, data):
        """
        selects an item in the combo
        :param data: what to select
        """
        self.combo.select(data)

    def enable_advanced(self):
        self.pack_start(self.mode, False, False, 6)
        self.reorder_child(self.mode, 1)
        self.mode.show()

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, combo):
        if not self._block_updates:
            self.emit('changed')

    def _on_combo__content_changed(self, mode):
        if not self._block_updates:
            self.emit('changed')
コード例 #42
0
ファイル: test_ComboBox.py プロジェクト: rcaferraz/kiwi
class TestComboBox(unittest.TestCase):
    def setUp(self):
        self.combo = ProxyComboBox()

    def _prefill(self):
        self.combo.prefill((('Johan', 1981),
                            ('Lorenzo', 1979),
                            ('Christian', 1976)))

    def testPrefill(self):
        self.combo.prefill(('foo', 'bar'))
        model = self.combo.get_model()
        self.assertEqual(tuple(model[0]), ('foo', None))
        self.assertEqual(tuple(model[1]), ('bar', None))

    def testPrefillWithData(self):
        self.combo.prefill((('foo', 42), ('bar', 138)))
        model = self.combo.get_model()
        self.assertEqual(tuple(model[0]), ('foo', 42))
        self.assertEqual(tuple(model[1]), ('bar', 138))
        self.combo.prefill([])
        self.assertEqual(len(self.combo.get_model()), 0)
        self.assertEqual(len(model), 0)
        self.assertEqual(len(self.combo), 0)

    def testSelectItemByPosition(self):
        self._prefill()
        self.combo.select_item_by_position(1)
        model = self.combo.get_model()
        iter = self.combo.get_active_iter()
        self.assertEqual(model.get_value(iter, 0), 'Lorenzo')
        self.assertEqual(model.get_value(iter, 1), 1979)
        self.assertRaises(KeyError, self.combo.select_item_by_label, 4)

    def testSelectItemByLabel(self):
        self._prefill()
        self.combo.select_item_by_label('Christian')
        model = self.combo.get_model()
        iter = self.combo.get_active_iter()
        rowNo = model.get_path(iter)[0]
        self.assertEqual(rowNo, 2)
        self.assertRaises(KeyError, self.combo.select_item_by_label, 'Salgado')

    def testSelectByData(self):
        self._prefill()
        self.combo.select_item_by_data(1976)
        model = self.combo.get_model()
        iter = self.combo.get_active_iter()
        rowNo = model.get_path(iter)[0]
        self.assertEqual(rowNo, 2)
        self.assertEqual(model.get_value(iter, 0), 'Christian')
        self.assertEqual(model.get_value(iter, 1), 1976)
        self.assertRaises(KeyError, self.combo.select_item_by_data, 1980)

    def testGetSelectedData(self):
        self._prefill()
        self.combo.select_item_by_position(0)
        self.assertEqual(self.combo.get_selected_data(), 1981)
        self.assertRaises(TypeError,
                          self.combo.select_item_by_position, 'foobar')

    def testGetSelectedLabel(self):
        self._prefill()

    def testClear(self):
        self._prefill()
        self.combo.clear()
        self.assertEqual(map(list, self.combo.get_model()), [])
コード例 #43
0
class StringSearchFilter(SearchFilter):
    """
    Contains:

      - a label
      - an entry

    :ivar entry: the entry
    :ivar label: the label
    """
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = HintedEntry()
        self.entry.set_hint(_("Search"))
        self.entry.show_hint()
        self.entry.props.secondary_icon_sensitive = False
        data = environ.get_resource_string('stoq', 'pixmaps',
                                           'stoq-funnel-16x16.png')
        image = pixbuf_from_string(data)
        self.entry.set_icon_from_pixbuf(gtk.ENTRY_ICON_PRIMARY,
                                        image)
        self.entry.set_icon_tooltip_text(gtk.ENTRY_ICON_PRIMARY,
                                         _("Add a filter"))
        self.entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY,
                                       gtk.STOCK_CLEAR)
        self.entry.set_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in (ContainsAll, ContainsExactly, DoesNotContain):
            self._add_option(option)
        self.mode.select_item_by_position(0)

    def _add_option(self, option_type, position=-2):
        option = option_type()
        num = abs(position)
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, combo):
        self.emit('changed')

    def _on_entry__activate(self, entry):
        self.emit('changed')

    def _on_entry__changed(self, entry):
        entry.props.secondary_icon_sensitive = bool(entry.get_text())

    def _position_filter_menu(self, data):
        window = self.entry.get_icon_window(gtk.ENTRY_ICON_PRIMARY)
        x, y = window.get_origin()
        y += window.get_size()[1]
        border = self.entry.style_get_property('progress-border')
        if border is not None:
            y += border.bottom
        return (x, y, True)

    def _on_entry__icon_release(self, entry, icon_pos, event):
        if icon_pos == gtk.ENTRY_ICON_SECONDARY:
            entry.set_text("")
            entry.grab_focus()
            self.emit('changed')
        elif icon_pos == gtk.ENTRY_ICON_PRIMARY:
            # We don't need create popup filters if haven't search columns.
            if (not self._container or not hasattr(self._container, 'menu') or
                not self._container.menu):
                return
            self._container.menu.popup(None, None,
                                       self._position_filter_menu, 0, event.time)

    #
    # SearchFilter
    #

    def get_state(self):
        option = self.mode.get_selected_data()
        return StringQueryState(filter=self,
                                text=unicode(self.entry.get_text()),
                                mode=option and option.mode)

    def set_state(self, text, mode=None):
        self.entry.set_text(text)
        if mode is not None:
            self.mode.select_item_by_position(mode)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = self.entry.get_text()
        if desc:
            mode = self.mode.get_selected_label()
            return '%s %s "%s"' % (self.title_label.get_text(), mode, desc,)

    #
    # Public API
    #

    def enable_advanced(self):
        # Do not show the funnel icon if its an advanced filter
        self.entry.set_icon_from_pixbuf(gtk.ENTRY_ICON_PRIMARY, None)
        self.mode.show()

    def set_label(self, label):
        self.title_label.set_text(label)
コード例 #44
0
class DateSearchFilter(SearchFilter):
    """
    A filter which helps you to search by a date interval.
    Can be customized through add_option.
    """
    __gtype_name__ = 'DateSearchFilter'

    class Type(enum):
        (USER_DAY, USER_INTERVAL) = range(100, 102)

    def __init__(self, label=''):
        """
        Create a new DateSearchFilter object.
        :param label: name of the search filter
        """
        self._options = {}
        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.from_label = Gtk.Label(label=_("From:"))
        self.pack_start(self.from_label, False, False, 0)
        self.from_label.show()

        self.start_date = ProxyDateEntry()
        self._start_changed_id = self.start_date.connect(
            'content-changed', self._on_start_date__changed)
        self.pack_start(self.start_date, False, False, 6)
        self.start_date.show()

        self.to_label = Gtk.Label(label=_("To:"))
        self.pack_start(self.to_label, False, False, 0)
        self.to_label.show()

        self.end_date = ProxyDateEntry()
        self._end_changed_id = self.end_date.connect(
            'content-changed', self._on_end_date__changed)
        self.pack_start(self.end_date, False, False, 6)
        self.end_date.show()

        self.add_custom_options()

        for option in (Any, Today, Yesterday, LastWeek, LastMonth):
            self.add_option(option)

        self.mode.select_item_by_position(0)

    #
    # SearchFilter
    #

    def get_state(self):
        start = self.start_date.get_date()
        end = self.end_date.get_date()
        if start == end:
            return DateQueryState(filter=self, date=start)
        return DateIntervalQueryState(filter=self, start=start, end=end)

    def set_state(self, start, end=None):
        self.start_date.set_date(start)
        if end is not None:
            self.end_date.set_date(end)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = ''
        start_date = self.start_date.get_date()
        end_date = self.end_date.get_date()
        if start_date:
            if end_date and start_date != end_date:
                desc += ' %s %s %s %s' % (
                    _(u'from'),
                    start_date.strftime('%x'),
                    _(u'to'),
                    end_date.strftime('%x'),
                )

            else:
                desc += start_date.strftime('%x')
        if desc:
            return '%s %s' % (
                self.get_title_label().get_text(),
                desc,
            )

    #
    # Public API
    #

    def clear_options(self):
        """
        Removes all previously added options
        """
        self._options = {}
        self.mode.clear()

    def add_option(self, option_type, position=-2):
        """
        Adds a date option
        :param option_type: option to add
        :type option_type: a :class:`DateSearchOption` subclass
        """
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option

    def add_option_fixed(self, name, date, position=-2):
        """
        Adds a fixed option, eg one for which date is not
        possible to modify.
        :param name: name of the option
        :param date: fixed data
        :param position: position to add the option at
        """
        option_type = type('', (FixedDateSearchOption, ),
                           dict(name=name, date=date))
        self.add_option(option_type, position=position)

    def add_option_fixed_interval(self, name, start, end, position=-2):
        """
        Adds a fixed option interval, eg one for which the dates are not
        possible to modify.
        :param name: name of the option
        :param start: start of the fixed interval
        :param end: end of the fixed interval
        :param position: position to add the option at
        """
        option_type = type('', (FixedIntervalSearchOption, ),
                           dict(name=name, start=start, end=end))
        self.add_option(option_type, position=position)

    def add_custom_options(self):
        """Adds the custom options 'Custom day' and 'Custom interval' which
        let the user define its own interval dates.
        """
        pos = len(self.mode) + 1
        for name, option_type in [
            (_('Custom day'), DateSearchFilter.Type.USER_DAY),
            (_('Custom interval'), DateSearchFilter.Type.USER_INTERVAL)
        ]:

            self.mode.insert_item(pos, name, option_type)
            pos += 1

    def get_start_date(self):
        """
        Get the start date.
        :returns: start date
        :rtype: datetime.date or None
        """
        return self.start_date.get_date()

    def get_end_date(self):
        """
        Get the end date.
        :returns: end date
        :rtype: datetime.date or None
        """
        return self.end_date.get_date()

    def set_use_date_entries(self, use_date_entries):
        """
        Toggles the visibility of the user selectable date entries
        :param use_date_entries:
        """
        self.from_label.props.visible = use_date_entries
        self.to_label.props.visible = use_date_entries
        self.start_date.props.visible = use_date_entries
        self.end_date.props.visible = use_date_entries

    def select(self, data=None, position=None):
        """
        selects an item in the combo
        Data or position can be sent in. If nothing
        is sent in the first item will be selected, if any

        :param data: data to select
        :param position: position of data to select
        """
        if data is not None and position is not None:
            raise TypeError("You can't send in both data and position")

        if data is None and position is None:
            position = 0

        if position is not None:
            if len(self.mode):
                self.mode.select_item_by_position(position)
        elif data:
            self.mode.select(data)

    #
    # Private
    #

    def _update_dates(self):
        # This is called when we change mode
        date_type = self.mode.get_selected_data()
        if date_type is None:
            return

        # If we switch to a user selectable day, make sure that
        # both dates are set to today
        if date_type == DateSearchFilter.Type.USER_DAY:
            today = datetime.date.today()
            self.start_date.set_date(today)
            self.end_date.set_date(today)
        # And for user interval, set start to today and to tomorrow
        elif date_type == DateSearchFilter.Type.USER_INTERVAL:
            today = datetime.date.today()
            self.start_date.set_date(today)
            self.end_date.set_date(today + datetime.timedelta(days=1))
        # Finally for pre-defined ones let the DateSearchOption decide what the
        # values are going to be, these dates are not user editable so
        # we don't need to do any checking.
        else:
            option = self._options.get(date_type)
            assert option, (date_type, self._options)
            start_date, end_date = option.get_interval()
            self.start_date.set_date(start_date)
            self.end_date.set_date(end_date)

    def _update_sensitivity(self):
        date_type = self.mode.get_selected_data()
        enabled = date_type == DateSearchFilter.Type.USER_INTERVAL
        self.to_label.set_sensitive(enabled)
        self.end_date.set_sensitive(enabled)

        enabled = (date_type == DateSearchFilter.Type.USER_INTERVAL
                   or date_type == DateSearchFilter.Type.USER_DAY)
        self.from_label.set_sensitive(enabled)
        self.start_date.set_sensitive(enabled)

    def _internal_set_start_date(self, date):
        self.start_date.handler_block(self._start_changed_id)
        self.start_date.set_date(date)
        self.start_date.handler_unblock(self._start_changed_id)

    def _internal_set_end_date(self, date):
        self.end_date.handler_block(self._end_changed_id)
        self.end_date.set_date(date)
        self.end_date.handler_unblock(self._end_changed_id)

    def _restore_date_validation(self):
        self.start_date.set_valid()
        self.end_date.set_valid()

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, mode):
        self._update_dates()
        self._update_sensitivity()
        self._restore_date_validation()
        self.emit('changed')

    def _on_start_date__changed(self, start_date):
        date_type = self.mode.get_selected_data()
        start = start_date.get_date()
        # For user days, just make sure that the date entries
        # always are in sync
        if date_type == DateSearchFilter.Type.USER_DAY:
            if start is None:
                self.start_date.set_invalid(_(u'Invalid date'))
            else:
                self.start_date.set_valid()
                self._internal_set_end_date(start)
        # Make sure that we cannot select a start date after
        # the end date, be nice and increase the end date if
        # the start date happen to be the same
        elif date_type == DateSearchFilter.Type.USER_INTERVAL:
            end = self.end_date.get_date()
            if start is None:
                self.start_date.set_invalid(_(u'Invalid date'))
                return
            if end and start >= end:
                self._internal_set_end_date(start + datetime.timedelta(days=1))

            self.start_date.set_valid()

    def _on_end_date__changed(self, end_date):
        date_type = self.mode.get_selected_data()
        # We don't need to do anything for user day, since
        # this the end date widget is disabled
        if date_type == DateSearchFilter.Type.USER_DAY:
            pass
        # Make sure that we cannot select an end date before
        # the start date, be nice and decrease the start date if
        # the end date happen to be the same
        elif date_type == DateSearchFilter.Type.USER_INTERVAL:
            start = self.start_date.get_date()
            end = end_date.get_date()
            if end is None:
                self.end_date.set_invalid(_(u'Invalid date'))
            else:
                self.end_date.set_valid()

            if start and end and end <= start:
                self._internal_set_start_date(end - datetime.timedelta(days=1))
コード例 #45
0
ファイル: chartdialog.py プロジェクト: leandrorchaves/stoq
class ChartDialog(gtk.Window):
    def __init__(self):
        self._js_data = None
        self._js_options = None
        self._current = None

        gtk.Window.__init__(self)
        self.set_size_request(800, 480)

        self.vbox = gtk.VBox()
        self.add(self.vbox)
        self.vbox.show()

        hbox = gtk.HBox()
        self.vbox.pack_start(hbox, False, False, 6)
        hbox.show()

        label = gtk.Label('Period:')
        hbox.pack_start(label, False, False, 6)
        label.show()

        self.chart_type = ProxyComboBox()
        self.chart_type.connect(
            'content-changed',
            self._on_chart_type__content_changed)
        hbox.pack_start(self.chart_type, False, False, 6)
        self.chart_type.show()

        self.period_values = ProxyComboBox()
        self.period_values.connect(
            'content-changed',
            self._on_period_values__content_changed)
        hbox.pack_start(self.period_values, False, False, 6)
        self.period_values.show()

        self._view = WebView()
        self._view.get_view().connect(
            'load-finished',
            self._on_view__document_load_finished)
        self.vbox.pack_start(self._view, True, True)

        self.results = ObjectList()
        self.results.connect(
            'row-activated',
            self._on_results__row_activated)
        self.vbox.pack_start(self.results, True, True)

        self._setup_daemon()

    @api.async
    def _setup_daemon(self):
        daemon = yield start_daemon()
        self._daemon_uri = daemon.base_uri

        proxy = daemon.get_client()
        yield proxy.callRemote('start_webservice')

        self.chart_type.prefill([
            ('Year', 'YearlyPayments'),
            ('Month', 'MonthlyPayments'),
            ('Day', 'DailyPayments'),
        ])

    @api.async
    def _invoke_chart(self, chart_type_name, **report_kwargs):
        def _get_chart_url(**kwargs):
            params = []
            for key, value in kwargs.items():
                params.append(key + '=' + str(value))
            return '%s/web/chart.json?%s' % (
                self._daemon_uri, '&'.join(params))

        url = _get_chart_url(type=chart_type_name, **report_kwargs)
        page = yield getPage(url)
        data = json.loads(page)
        api.asyncReturn(data)

    def _render_chart(self, chart_class, response):
        self._render_javascript(chart_class, response)
        self._render_objectlist(chart_class, response)

    def _render_javascript(self, chart_class, response):
        ticks = [item['short_title'] for item in response['items']]

        self._js_data = response['data']

        options = {}
        options['description'] = response['description']
        options['series'] = [dict(label=c['title']) for c in chart_class.columns][1:]
        options['xaxis_ticks'] = ticks
        self._js_options = options

        self._view.load_uri('%s/web/static/chart.html' % (
                            self._daemon_uri,))

    def _render_objectlist(self, chart_class, response):
        columns = []
        for kwargs in chart_class.columns:
            kwargs = kwargs.copy()
            name = kwargs.pop('name')
            columns.append(Column(name, **kwargs))
        self.results.set_columns(columns)

        items = []
        for item in response['items']:
            settable = Settable(**item)
            settable.chart_class = chart_class
            items.append(settable)
        self.results.add_list(items, clear=True)
        self.results.show()

    def _load_finished(self):
        self._view.js_function_call(
            "plot", self._js_data, self._js_options)

    @api.async
    def _show_one(self, chart_type_name, start, end):
        chart_class = get_chart_class(chart_type_name)
        report_kwargs = dict(start=start.strftime('%Y-%m-%d'),
                             end=end.strftime('%Y-%m-%d'))

        # Get chart datab
        response = yield self._invoke_chart(chart_type_name, **report_kwargs)
        self._render_chart(chart_class, response)

    def _update_period_values(self):
        chart_type_name = self.chart_type.get_selected()
        chart_class = get_chart_class(chart_type_name)
        values = chart_class.get_combo_labels()
        self.period_values.prefill(values)

    #
    # Callbacks
    #

    def _on_view__document_load_finished(self, view, frame):
        self._load_finished()

    def _on_chart_type__content_changed(self, combo):
        self._update_period_values()

    def _on_period_values__content_changed(self, combo):
        kind = self.chart_type.get_selected()
        value = self.period_values.get_selected()
        if not value:
            return
        start, end = value
        if self._current == (kind, start, end):
            return
        self._show_one(kind, start, end)
        self._current = kind, start, end

    def _on_results__row_activated(self, results, item):
        chart_type_name = item.chart_class.__name__
        if chart_type_name == 'YearlyPayments':
            start = localdate(item.year, 1, 1).date()
            end = localdate(item.year, 12, 31).date()
            chart_type_name = 'MonthlyPayments'
        elif chart_type_name == 'MonthlyPayments':
            start = localdate(item.year, item.month, 1).date()
            end = start + relativedelta(days=31)
            chart_type_name = 'DailyPayments'
        else:
            return
        self._show_one(chart_type_name, start, end)
コード例 #46
0
class NumberSearchFilter(SearchFilter):
    """
    A filter which helps you to search by a number interval.
    """
    __gtype_name__ = 'NumberSearchFilter'

    def __init__(self, label=''):
        """
        Create a new NumberSearchFilter object.
        :param label: name of the search filter
        """

        self._options = {}

        SearchFilter.__init__(self, label=label)
        self.title_label = Gtk.Label(label=label)
        self.title_label.set_alignment(1.0, 0.5)
        self.pack_start(self.title_label, False, False, 0)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.start = Gtk.SpinButton(climb_rate=1.0)
        self.start.get_adjustment().step_increment = 1.0
        self.start.set_range(-MAX_INT - 1, MAX_INT)
        self.pack_start(self.start, False, False, 6)
        self.start.show()
        self.start.connect_after('activate', self._on_entry__activate)

        self.and_label = Gtk.Label(label=_("And"))
        self.pack_start(self.and_label, False, False, 0)
        self.and_label.show()

        self.end = Gtk.SpinButton(climb_rate=1.0)
        self.end.get_adjustment().step_increment = 1.0
        self.end.set_range(-MAX_INT - 1, MAX_INT)
        self.pack_start(self.end, False, False, 6)
        self.end.show()
        self.end.connect_after('activate', self._on_entry__activate)

        for option in (LowerThan, EqualsTo, GreaterThan, Between):
            self.add_option(option)

        self.mode.select_item_by_position(0)

    def set_digits(self, digits):
        """
        Number of decimal place to be displayed
        :param digits: number of decimal places
        """
        self.start.set_digits(digits)
        self.end.set_digits(digits)

    #
    #   Private
    #

    def _update_visibility(self):
        option = self.mode.get_selected_data()
        numbers = option.numbers
        if numbers == 0:
            self.start.hide()
            self.and_label.hide()
            self.end.hide()
        elif numbers == 1:
            self.start.show()
            self.and_label.hide()
            self.end.hide()
        elif numbers == 2:
            self.start.show()
            self.and_label.show()
            self.end.show()

    #
    #   Callbacks
    #

    def _on_entry__activate(self, entry):
        self.emit('changed')

    def _on_mode__content_changed(self, combo):
        self._update_visibility()
        self.emit('changed')

    #
    #   SearchFilter
    #

    def get_state(self):
        # Using Decimals for better precision.
        start_value = Decimal("%.2f" % self.start.get_value())
        end_value = Decimal("%.2f" % self.end.get_value())
        option = self.mode.get_selected_data()

        start, end = option().get_interval(start_value, end_value)
        return NumberIntervalQueryState(filter=self, start=start, end=end)

    def set_state(self, start, end):
        self.start.set_value(start)
        self.end.set_value(end)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = ''
        option = self.mode.get_selected_data()
        if option is not None:
            desc += option.name
            if option.numbers > 0:
                start = self.start.get_value_as_int()
                if option.numbers == 1:
                    desc += ' %d' % start
                elif option.numbers == 2:
                    end = self.end.get_value_as_int()
                    desc += ' %d %s %d' % (
                        start,
                        self.and_label.get_text(),
                        end,
                    )
        if desc:
            return '%s %s' % (self.get_title_label().get_text(), desc)

    #
    #   Public API
    #

    def add_option(self, option_type, position=-2):
        """
        Adds a date option
        :param option_type: option to add
        :type option_type: a :class:`NumberSearchOption` subclass
        """
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option
コード例 #47
0
class ComboSearchFilter(SearchFilter):
    """
    - a label
    - a combo with a set of predefined item to select from
    """
    __gtype_name__ = 'ComboSearchFilter'

    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        # We create the mode, but it will only be added to this box when
        # enable_advanced is called
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        for option in (ComboEquals, ComboDifferent):
            self.add_option(option)
        self.mode.select_item_by_position(0)

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()

    #
    # SearchFilter
    #

    def get_state(self):
        value = self.combo.get_selected_data()
        mode = self.mode.get_selected_data()
        state = NumberQueryState(filter=self, value=value, mode=mode.mode)
        if hasattr(value, 'id'):
            state.value_id = value.id
        return state

    def set_state(self, value, value_id=None, mode=None):
        if mode is None:
            mode = NumberQueryState.EQUALS
        if value_id is not None:
            for item in self.combo.get_model_items().values():
                if item is None:
                    continue
                if item.id == value_id:
                    value = item
                    break
        self.select(value)

    def update_values(self, values):
        self._block_updates = True
        self.combo.prefill(values)
        self._block_updates = False

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.combo

    def get_description(self):
        desc = ''
        data = self.combo.get_selected_data()
        if data is not None:
            desc += self.combo.get_selected_label()
            return '%s %s' % (self.title_label.get_text(), desc,)

    #
    # Public API
    #

    def add_option(self, option_type, position=0):
        """
        Adds an option
        :param option_type: option to add
        :type option_type: a :class:`ComboSearchOption` subclass
        """
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)

    def select(self, data):
        """
        selects an item in the combo
        :param data: what to select
        """
        self.combo.select(data)

    def enable_advanced(self):
        self.pack_start(self.mode, False, False, 6)
        self.reorder_child(self.mode, 1)
        self.mode.show()

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, combo):
        if not self._block_updates:
            self.emit('changed')

    def _on_combo__content_changed(self, mode):
        if not self._block_updates:
            self.emit('changed')
コード例 #48
0
ファイル: accounteditor.py プロジェクト: ComradeHadi/stoq
class AccountEditor(BaseEditor):
    """ Account Editor """
    gladefile = "AccountEditor"
    proxy_widgets = ['description', 'code']
    model_type = Account
    model_name = _('Account')

    def __init__(self, store, model=None, parent_account=None):
        self._last_account_type = None
        self._bank_number = -1
        self._bank_widgets = []
        self._bank_option_widgets = []
        self._option_fields = {}
        self._test_button = None
        self.existing = model is not None
        self.parent_account = parent_account
        self.bank_model = _TemporaryBankAccount()
        BaseEditor.__init__(self, store, model)

        action_area = self.main_dialog.action_area
        action_area.set_layout(Gtk.ButtonBoxStyle.END)
        action_area.pack_start(self._test_button, False, False, 0)
        action_area.set_child_secondary(self._test_button, True)
        self._test_button.show()

    #
    # BaseEditor hooks
    #

    def create_model(self, store):
        return Account(description=u"",
                       account_type=Account.TYPE_CASH,
                       store=store)

    def _setup_widgets(self):
        self._test_button = Gtk.Button(_("Print a test bill"))
        self._test_button.connect('clicked', self._on_test_button__clicked)
        self.parent_accounts = AccountTree(with_code=False, create_mode=True)
        self.parent_accounts.connect(
            'selection-changed', self._on_parent_accounts__selection_changed)
        self.tree_box.pack_start(self.parent_accounts, True, True, 0)
        self.tree_box.reorder_child(self.parent_accounts, 0)

        if sysparam.compare_object('IMBALANCE_ACCOUNT', self.model):
            self.account_type.set_sensitive(False)

        self.account_type.prefill(Account.account_type_descriptions)
        account_type = self.model.account_type

        self.parent_accounts.insert_initial(self.store,
                                            edited_account=self.model)
        if self.parent_account:
            account = self.parent_accounts.get_account_by_id(
                self.parent_account.id)
            self.parent_accounts.select(account)
            if not self.existing:
                account_type = account.account_type
        self.account_type.select(account_type)
        self.parent_accounts.show()

    def setup_proxies(self):
        self._setup_widgets()
        self.add_proxy(self.model, AccountEditor.proxy_widgets)

    def validate_confirm(self):
        if not self.model.description:
            return False
        account = self.parent_accounts.get_selected()
        if not account:
            return True
        return account.selectable

    def on_confirm(self):
        new_parent = self.parent_accounts.get_selected()
        if new_parent:
            new_parent = new_parent.account
        if new_parent != self.model:
            self.model.parent = new_parent
        self.model.account_type = self.account_type.get_selected()
        self._save_bank()

    def refresh_ok(self, value):
        BaseEditor.refresh_ok(self, value)

        account_type = self.account_type.get_selected()
        if account_type != Account.TYPE_BANK:
            value = False
        self._test_button.set_sensitive(value)

    # Private

    def _save_bank(self):
        bank_account = self.model.bank
        if not bank_account:
            bank_account = BankAccount(account=self.model, store=self.store)
        # FIXME: Who sets this to a str?
        bank_account.bank_account = unicode(self.bank_model.bank_account)
        bank_account.bank_branch = unicode(self.bank_model.bank_branch)
        if self._bank_number is not None:
            bank_account.bank_number = self.bank_model.bank_number

        self._save_bank_bill_options(bank_account)

    def _save_bank_bill_options(self, bank_account):
        for option, entry in self._option_fields.items():
            value = unicode(entry.get_text())
            bill_option = self.store.find(BillOption,
                                          bank_account=bank_account,
                                          option=option).one()
            if bill_option is None:
                bill_option = BillOption(store=self.store,
                                         bank_account=bank_account,
                                         option=option,
                                         value=value)
            bill_option.value = value

    def _add_widget(self, label, widget, options=False):
        n_rows = self.table.props.n_rows
        l = Gtk.Label()
        l.set_markup(label)
        l.props.xalign = 1.0
        self.table.resize(n_rows + 1, 2)
        self.table.attach(l, 0, 1, n_rows, n_rows + 1, Gtk.AttachOptions.FILL,
                          0, 0, 0)
        self.table.attach(widget, 1, 2, n_rows, n_rows + 1,
                          Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0,
                          0, 0)
        if options:
            self._bank_option_widgets.extend([l, widget])
        else:
            self._bank_widgets.extend([l, widget])
        l.show()
        return l

    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 _fill_bank_account(self):
        if not self.model.bank:
            return

        self.bank_model.bank_branch = self.model.bank.bank_branch.encode(
            'utf-8')
        self.bank_model.bank_account = self.model.bank.bank_account.encode(
            'utf-8')
        self.bank_proxy.update('bank_branch')
        self.bank_proxy.update('bank_account')

        bill_options = list(
            self.store.find(BillOption, bank_account=self.model.bank))
        for bill_option in bill_options:
            if bill_option.option is None:
                continue
            field_entry = self._option_fields.get(bill_option.option)
            if field_entry:
                field_entry.set_text(bill_option.value)

    def _update_account_type(self, account_type):
        if not self.account_type.get_sensitive():
            return
        if account_type != Account.TYPE_BANK:
            self._remove_bank_widgets()
            self._remove_bank_option_widgets()
            self.code.set_sensitive(True)
            return

        self.code.set_sensitive(False)
        self.bank_type = ProxyComboBox()
        self._add_widget(api.escape(_("Bank:")), self.bank_type)
        self.bank_type.connect('content-changed',
                               self._on_bank_type__content_changed)
        self.bank_type.show()

        banks = [(_('Generic'), None)]
        banks.extend([(b.description, b.bank_number) for b in get_all_banks()])
        self.bank_type.prefill(banks)

        if self.model.bank:
            try:
                self.bank_type.select(self.model.bank.bank_number)
            except KeyError:
                self.bank_type.select(None)

        self._update_bank_type()

    def _remove_bank_widgets(self):
        for widget in self._bank_widgets:
            widget.get_parent().remove(widget)
            widget.destroy()
        self.table.resize(5, 2)
        self._bank_widgets = []

    def _remove_bank_option_widgets(self):
        for widget in self._bank_option_widgets:
            widget.get_parent().remove(widget)
            widget.destroy()
        self.table.resize(5 + len(self._bank_widgets) / 2, 2)
        self._bank_option_widgets = []
        self._option_fields = {}

    def _print_test_bill(self):
        try:
            bank_info = get_bank_info_by_number(self.bank_model.bank_number)
        except NotImplementedError:
            info(_("This bank does not support printing of bills"))
            return
        kwargs = dict(
            valor_documento=12345.67,
            data_vencimento=datetime.date.today(),
            data_documento=datetime.date.today(),
            data_processamento=datetime.date.today(),
            nosso_numero=u'24533',
            numero_documento=u'1138',
            sacado=[_(u"Drawee"), _(u"Address"),
                    _(u"Details")],
            cedente=[_(u"Supplier"),
                     _(u"Address"),
                     _(u"Details"), ("CNPJ")],
            demonstrativo=[_(u"Demonstration")],
            instrucoes=[_(u"Instructions")],
            agencia=self.bank_model.bank_branch,
            conta=self.bank_model.bank_account,
        )
        for opt in self.bank_model.options:
            kwargs[opt.option] = opt.value
        data = bank_info(**kwargs)
        print_report(BillTestReport, data)

    # Callbacks

    def _on_parent_accounts__selection_changed(self, objectlist, account):
        self.force_validation()

    def on_description__activate(self, entry):
        if self.validate_confirm():
            self.confirm()

    def on_description__validate(self, entry, text):
        if not text:
            return ValidationError(_("Account description cannot be empty"))

    def on_account_type__content_changed(self, account_type):
        account_type = account_type.get_selected()
        if self._last_account_type == account_type:
            return
        self._update_account_type(account_type)
        self._last_account_type = account_type

    def _on_bank_type__content_changed(self, bank_type):
        bank_number = bank_type.get_selected()
        if self._bank_number == bank_number:
            return
        self._update_bank_type()

        self._bank_number = bank_number

    def _on_bank_branch__validate(self, entry, value, bank_info):
        if bank_info:
            try:
                bank_info.validate_field(value)
            except BoletoException as e:
                return ValidationError(str(e))

    def _on_bank_account__validate(self, entry, value, bank_info):
        if bank_info:
            try:
                bank_info.validate_field(value)
            except BoletoException as e:
                return ValidationError(str(e))

    def _on_bank_option__validate(self, entry, value, bank_info, option):
        try:
            bank_info.validate_option(option, value)
        except BoletoException as e:
            return ValidationError(str(e))
        self.bank_model.set_option(option, value)

    def _on_test_button__clicked(self, button):
        self._print_test_bill()
コード例 #49
0
class WorkOrderQuoteItemStep(SaleQuoteItemStep):
    """Third step for work order pre-sales

    Just like :class:`stoqlib.gui.wizards.salequotewizard.SaleQuoteItemStep`,
    but each item added here will be added to a workorder too (selected
    on a combo).
    """

    #
    #  Public API
    #

    def get_extra_columns(self):
        """Get some extra columns for the items list

        Subclasses can override this and add some extra columns. Those
        columns will be added just after the 'description' and before
        the 'quantity' columns.
        """
        return [
            Column('_equipment',
                   title=_(u'Equipment'),
                   data_type=str,
                   ellipsize=Pango.EllipsizeMode.END)
        ]

    def setup_work_order(self, work_order):
        """Do some extra setup for the work order

        This is called at the initialization of this step. Subclasses can
        override this to do any extra setup they need on the work order.

        :param work_order: the |workorder| we are describing
        """

    #
    #  SaleQuoteItemStep
    #

    def setup_proxies(self):
        self._radio_group = None
        self._setup_work_orders_widgets()
        super(WorkOrderQuoteItemStep, self).setup_proxies()

    def get_order_item(self,
                       sellable,
                       price,
                       quantity,
                       batch=None,
                       parent=None):
        item = super(WorkOrderQuoteItemStep,
                     self).get_order_item(sellable,
                                          price,
                                          quantity,
                                          batch=batch,
                                          parent=parent)

        work_order = self._selected_workorder
        wo_item = work_order.add_sellable(sellable,
                                          price=price,
                                          batch=batch,
                                          quantity=quantity)
        wo_item.sale_item = item
        item._equipment = work_order.description

        return item

    def get_saved_items(self):
        for item in super(WorkOrderQuoteItemStep, self).get_saved_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            item._equipment = wo_item.order.description
            yield item

    def remove_items(self, items):
        # Remove the workorder items first to avoid reference problems
        for item in items:
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            # If the item's quantity_decreased changed in this step, the
            # synchronization between the 2 that happens on self.validate_step
            # would not have happened yet, meaning that order.remove_item
            # would try to return a wrong quantity to the stock. Force the
            # synchronization to avoid any problems like that
            wo_item.quantity_decreased = item.quantity_decreased
            wo_item.order.remove_item(wo_item)

        super(WorkOrderQuoteItemStep, self).remove_items(items)

    def get_columns(self):
        columns = [
            Column('sellable.code',
                   title=_(u'Code'),
                   data_type=str,
                   visible=False),
            Column('sellable.barcode',
                   title=_(u'Barcode'),
                   data_type=str,
                   visible=False),
            Column('sellable.description',
                   title=_('Description'),
                   data_type=str,
                   expand=True,
                   format_func=self._format_description,
                   format_func_data=True),
        ]
        columns.extend(self.get_extra_columns())
        columns.extend([
            Column('quantity',
                   title=_(u'Quantity'),
                   data_type=decimal.Decimal,
                   format_func=format_quantity),
            Column('base_price', title=_('Original Price'),
                   data_type=currency),
            Column('price', title=_('Sale Price'), data_type=currency),
            Column('sale_discount',
                   title=_('Discount'),
                   data_type=decimal.Decimal,
                   format_func=get_formatted_percentage),
            Column('total', title=_(u'Total'), data_type=currency),
        ])
        return columns

    def validate_step(self):
        # When finishing the wizard, make sure that all modifications on
        # sale items on this step are propagated to their work order items
        for sale_item in self.model.get_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item)
            wo_item.quantity = sale_item.quantity
            wo_item.quantity_decreased = sale_item.quantity_decreased
            wo_item.price = sale_item.price

        return super(WorkOrderQuoteItemStep, self).validate_step()

    #
    #  Private
    #

    def _format_description(self, item, data):
        return format_sellable_description(item.sellable, item.batch)

    def _setup_work_orders_widgets(self):
        self._work_orders_hbox = Gtk.HBox(spacing=6)
        self.item_vbox.pack_start(self._work_orders_hbox, False, True, 6)
        self.item_vbox.reorder_child(self._work_orders_hbox, 0)
        self._work_orders_hbox.show()

        label = Gtk.Label(label=_("Work order:"))
        self._work_orders_hbox.pack_start(label, False, True, 0)

        data = []
        for wo in self.wizard.workorders:
            # The work order might be already approved if we are editing a sale
            if wo.can_approve():
                wo.approve()

            self.setup_work_order(wo)
            data.append([wo.description, wo])

        if len(data) <= _MAX_WORK_ORDERS_FOR_RADIO:
            self.work_orders_combo = None
            for desc, wo in data:
                self._add_work_order_radio(desc, wo)
        else:
            self.work_orders_combo = ProxyComboBox()
            self.work_orders_combo.prefill(data)
            self._selected_workorder = self.work_orders_combo.get_selected()
            self._work_orders_hbox.pack_start(self.work_orders_combo, False,
                                              False, 0)

        self._work_orders_hbox.show_all()

    def _add_work_order_radio(self, desc, workorder):
        radio = Gtk.RadioButton(group=self._radio_group, label=desc)
        radio._workorder = workorder
        radio.connect('toggled', self._on_work_order_radio__toggled)

        if self._radio_group is None:
            self._radio_group = radio
            self._selected_workorder = workorder

        self._work_orders_hbox.pack_start(radio, False, False, 6)
        radio.show_all()

    #
    #  Callbacks
    #

    def on_work_orders_combo__content_changed(self, combo):
        self._selected_workorder = combo.get_selected()

    def _on_work_order_radio__toggled(self, radio):
        if not radio.get_active():
            return
        self._selected_workorder = radio._workorder
コード例 #50
0
class StringSearchFilter(SearchFilter):
    """
    Contains:

      - a label
      - an entry

    :ivar entry: the entry
    :ivar label: the label
    """
    def __init__(self, label, chars=0, container=None):
        """
        Create a new StringSearchFilter object.
        :param label: label of the search filter
        :param chars: maximum number of chars used by the search entry
        """
        self._container = container
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = HintedEntry()
        self.entry.set_hint(_("Search"))
        self.entry.show_hint()
        self.entry.props.secondary_icon_sensitive = False
        self.entry.set_icon_from_stock(gtk.ENTRY_ICON_PRIMARY, gtk.STOCK_FIND)
        self.entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY,
                                       gtk.STOCK_CLEAR)
        self.entry.set_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY,
                                         _("Clear the search"))
        self.entry.connect("icon-release", self._on_entry__icon_release)
        self.entry.connect('activate', self._on_entry__activate)
        self.entry.connect('changed', self._on_entry__changed)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in (ContainsAll, ContainsExactly, DoesNotContain):
            self._add_option(option)
        self.mode.select_item_by_position(0)

    def _add_option(self, option_type, position=-2):
        option = option_type()
        num = abs(position)
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, combo):
        self.emit('changed')

    def _on_entry__activate(self, entry):
        self.emit('changed')

    def _on_entry__changed(self, entry):
        entry.props.secondary_icon_sensitive = bool(entry.get_text())

    def _position_filter_menu(self, data):
        window = self.entry.get_icon_window(gtk.ENTRY_ICON_PRIMARY)
        x, y = window.get_origin()
        y += window.get_size()[1]
        border = self.entry.style_get_property('progress-border')
        if border is not None:
            y += border.bottom
        return (x, y, True)

    def _on_entry__icon_release(self, entry, icon_pos, event):
        if icon_pos == gtk.ENTRY_ICON_SECONDARY:
            entry.set_text("")
            entry.grab_focus()
            self.emit('changed')
        elif icon_pos == gtk.ENTRY_ICON_PRIMARY:
            # We don't need create popup filters if haven't search columns.
            if (not self._container or not hasattr(self._container, 'menu')
                    or not self._container.menu):
                return
            self._container.menu.popup(None, None, self._position_filter_menu,
                                       0, event.time)

    #
    # SearchFilter
    #

    def get_state(self):
        option = self.mode.get_selected_data()
        return StringQueryState(filter=self,
                                text=self.entry.get_text(),
                                mode=option and option.mode)

    def set_state(self, text, mode=None):
        self.entry.set_text(text)
        if mode is not None:
            self.mode.select_item_by_position(mode)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = self.entry.get_text()
        if desc:
            mode = self.mode.get_selected_label()
            return '%s %s "%s"' % (
                self.title_label.get_text(),
                mode,
                desc,
            )

    #
    # Public API
    #

    def enable_advanced(self):
        self.mode.show()

    def set_label(self, label):
        self.title_label.set_text(label)
コード例 #51
0
ファイル: search.py プロジェクト: hsavolai/vmlab
class StringSearchFilter(SearchFilter):
    """
    - a label
    - an entry
    @ivar entry: the entry
    @ivar label: the label
    """
    def __init__(self, label, chars=0):
        """
        Create a new StringSearchFilter object.
        @param label: label of the search filter
        @param chars: maximum number of chars used by the search entry
        """
        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self._options = {}
        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)

        self.entry = gtk.Entry()
        self.entry.connect('activate', self._on_entry__activate)
        if chars:
            self.entry.set_width_chars(chars)
        self.pack_start(self.entry, False, False, 6)
        self.entry.show()

        for option in (Contains, DoesNotContain):
            self._add_option(option)
        self.mode.select_item_by_position(0)

    def _add_option(self, option_type, position=-2):
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option

    #
    # Callbacks
    #

    def _on_mode__content_changed(self, combo):
        self.emit('changed')

    def _on_entry__activate(self, entry):
        self.emit('changed')

    #
    # SearchFilter
    #

    def get_state(self):
        option = self.mode.get_selected_data()
        return StringQueryState(filter=self,
                                text=self.entry.get_text(),
                                mode=option.mode)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = self.entry.get_text()
        if desc:
            mode = self.mode.get_selected_label()
            return '%s %s "%s"' % (self.title_label.get_text(), mode, desc,)

    #
    # Public API
    #

    def enable_advaced(self):
        self.mode.show()

    def set_label(self, label):
        self.title_label.set_text(label)
コード例 #52
0
class ComboSearchFilter(SearchFilter):
    """
    - a label
    - a combo with a set of predefined item to select from
    """
    __gtype_name__ = 'ComboSearchFilter'

    def __init__(self, label='', values=None):
        """
        Create a new ComboSearchFilter object.
        :param label: label of the search filter
        :param values: items to put in the combo, see
            :class:`kiwi.ui.widgets.combo.ProxyComboBox.prefill`
        """
        self._block_updates = False
        SearchFilter.__init__(self, label=label)
        label = gtk.Label(label)
        self.pack_start(label, False, False)
        label.show()
        self.title_label = label

        self.combo = ProxyComboBox()
        if values:
            self.update_values(values)
        self.combo.connect('content-changed', self._on_combo__content_changed)
        self.pack_start(self.combo, False, False, 6)
        self.combo.show()

    #
    # SearchFilter
    #

    def get_state(self):
        value = self.combo.get_selected_data()
        state = NumberQueryState(filter=self, value=value)
        if hasattr(value, 'id'):
            state.value_id = value.id
        return state

    def set_state(self, value, value_id=None):
        if value_id is not None:
            for item in self.combo.get_model_items().values():
                if item is None:
                    continue
                if item.id == value_id:
                    value = item
                    break
        self.select(value)

    def update_values(self, values):
        self._block_updates = True
        self.combo.prefill(values)
        self._block_updates = False

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.combo

    def get_description(self):
        desc = ''
        data = self.combo.get_selected_data()
        if data is not None:
            desc += self.combo.get_selected_label()
            return '%s %s' % (
                self.title_label.get_text(),
                desc,
            )

    #
    # Public API
    #

    def select(self, data):
        """
        selects an item in the combo
        :param data: what to select
        """
        self.combo.select(data)

    #
    # Callbacks
    #

    def _on_combo__content_changed(self, mode):
        if not self._block_updates:
            self.emit('changed')
コード例 #53
0
ファイル: test_ComboBox.py プロジェクト: rcaferraz/kiwi
 def setUp(self):
     self.combo = ProxyComboBox()
コード例 #54
0
ファイル: workorderquotewizard.py プロジェクト: pkaislan/stoq
class WorkOrderQuoteItemStep(SaleQuoteItemStep):
    """Third step for work order pre-sales

    Just like :class:`stoqlib.gui.wizards.salequotewizard.SaleQuoteItemStep`,
    but each item added here will be added to a workorder too (selected
    on a combo).
    """

    #
    #  Public API
    #

    def get_extra_columns(self):
        """Get some extra columns for the items list

        Subclasses can override this and add some extra columns. Those
        columns will be added just after the 'description' and before
        the 'quantity' columns.
        """
        return [Column('_equipment', title=_(u'Equipment'), data_type=str,
                       ellipsize=pango.ELLIPSIZE_END)]

    def setup_work_order(self, work_order):
        """Do some extra setup for the work order

        This is called at the initialization of this step. Subclasses can
        override this to do any extra setup they need on the work order.

        :param work_order: the |workorder| we are describing
        """

    #
    #  SaleQuoteItemStep
    #

    def setup_proxies(self):
        self._radio_group = None
        self._setup_work_orders_widgets()
        super(WorkOrderQuoteItemStep, self).setup_proxies()

    def get_order_item(self, sellable, price, quantity, batch=None):
        item = super(WorkOrderQuoteItemStep, self).get_order_item(
            sellable, price, quantity, batch=batch)

        work_order = self._selected_workorder
        wo_item = work_order.add_sellable(
            sellable, price=price, batch=batch, quantity=quantity)
        wo_item.sale_item = item
        item._equipment = work_order.description

        return item

    def get_saved_items(self):
        for item in super(WorkOrderQuoteItemStep, self).get_saved_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            item._equipment = wo_item.order.description
            yield item

    def remove_items(self, items):
        # Remove the workorder items first to avoid reference problems
        for item in items:
            wo_item = WorkOrderItem.get_from_sale_item(self.store, item)
            wo_item.order.remove_item(wo_item)

        super(WorkOrderQuoteItemStep, self).remove_items(items)

    def get_columns(self):
        columns = [
            Column('sellable.code', title=_(u'Code'),
                   data_type=str, visible=False),
            Column('sellable.barcode', title=_(u'Barcode'),
                   data_type=str, visible=False),
            Column('sellable.description', title=_('Description'),
                   data_type=str, expand=True,
                   format_func=self._format_description, format_func_data=True),
        ]
        columns.extend(self.get_extra_columns())
        columns.extend([
            Column('quantity', title=_(u'Quantity'),
                   data_type=decimal.Decimal, format_func=format_quantity),
            Column('base_price', title=_('Original Price'), data_type=currency),
            Column('price', title=_('Sale Price'), data_type=currency),
            Column('sale_discount', title=_('Discount'),
                   data_type=decimal.Decimal,
                   format_func=get_formatted_percentage),
            Column('total', title=_(u'Total'),
                   data_type=currency),
        ])
        return columns

    def validate_step(self):
        # When finishing the wizard, make sure that all modifications on
        # sale items on this step are propagated to their work order items
        for sale_item in self.model.get_items():
            wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item)
            wo_item.quantity = sale_item.quantity
            wo_item.quantity_decreased = sale_item.quantity_decreased
            wo_item.price = sale_item.price

        return super(WorkOrderQuoteItemStep, self).validate_step()

    #
    #  Private
    #

    def _format_description(self, item, data):
        return format_sellable_description(item.sellable, item.batch)

    def _setup_work_orders_widgets(self):
        self._work_orders_hbox = gtk.HBox(spacing=6)
        self.item_vbox.pack_start(self._work_orders_hbox, False, True, 6)
        self.item_vbox.reorder_child(self._work_orders_hbox, 0)
        self._work_orders_hbox.show()

        label = gtk.Label(_("Work order:"))
        self._work_orders_hbox.pack_start(label, False, True)

        data = []
        for wo in self.wizard.workorders:
            # The work order might be already approved if we are editing a sale
            if wo.can_approve():
                wo.approve()

            self.setup_work_order(wo)
            data.append([wo.description, wo])

        if len(data) <= _MAX_WORK_ORDERS_FOR_RADIO:
            self.work_orders_combo = None
            for desc, wo in data:
                self._add_work_order_radio(desc, wo)
        else:
            self.work_orders_combo = ProxyComboBox()
            self.work_orders_combo.prefill(data)
            self._selected_workorder = self.work_orders_combo.get_selected()
            self._work_orders_hbox.pack_start(self.work_orders_combo,
                                              False, False)

        self._work_orders_hbox.show_all()

    def _add_work_order_radio(self, desc, workorder):
        radio = gtk.RadioButton(group=self._radio_group, label=desc)
        radio.set_data('workorder', workorder)
        radio.connect('toggled', self._on_work_order_radio__toggled)

        if self._radio_group is None:
            self._radio_group = radio
            self._selected_workorder = workorder

        self._work_orders_hbox.pack_start(radio, False, False, 6)
        radio.show_all()

    #
    #  Callbacks
    #

    def on_work_orders_combo__content_changed(self, combo):
        self._selected_workorder = combo.get_selected()

    def _on_work_order_radio__toggled(self, radio):
        if not radio.get_active():
            return
        self._selected_workorder = radio.get_data('workorder')
コード例 #55
0
class MassEditorWidget(Gtk.HBox):
    _editors = {
        currency: DecimalEditor,
        Decimal: DecimalEditor,
        str: UnicodeEditor,
        datetime.date: DateEditor,
        object: ObjectEditor,
    }

    def __init__(self, store, fields, results):
        self._store = store
        self._editor = None
        self._fields = fields
        self._results = results
        super(MassEditorWidget, self).__init__(spacing=6)
        self._setup_widgets()

    def _filter_fields(self, data_type):
        return [f for f in self._fields if f.data_type == data_type]

    def _setup_editor(self, field):
        # Reuse editor if its possible (not when data_type is an object, since
        # that requires changing the reference values)
        if (self._editor and field.data_type is not object and
                self._editor.data_type == field.data_type):
            self._editor.set_field(field)
            return

        if self._editor:
            self.editor_placeholder.remove(self._editor)

        other_fields = self._filter_fields(field.data_type)
        klass = self._editors[field.data_type]
        self._editor = klass(self._store, field, other_fields)
        self.editor_placeholder.add(self._editor)

    def _setup_widgets(self):
        label = Gtk.Label(label=_('Update'))
        self.pack_start(label, False, False, 0)
        self.field_combo = ProxyComboBox()
        self.field_combo.connect('changed', self._on_field_combo__changed)
        self.pack_start(self.field_combo, False, False, 0)
        self.editor_placeholder = Gtk.EventBox()
        self.pack_start(self.editor_placeholder, False, False, 0)
        self.apply_button = Gtk.Button(stock=Gtk.STOCK_APPLY)
        self.apply_button.connect('clicked', self._on_apply_button__clicked)
        self.pack_start(self.apply_button, False, False, 0)

        for field in self._fields:
            # Don't let the user edit unique fields for now
            if field.unique or field.read_only:
                continue
            self.field_combo.append_item(field.label, field)
        self.field_combo.select_item_by_position(0)

    def _apply(self):
        marker('Updating values')
        for i in self._results:
            self._editor.apply_operation(i)
            self._results.refresh(i)
        marker('Done updating values')

    #
    # Public API
    #

    def get_changed_objects(self):
        """Returns a set of all the changed objects"""
        objs = set()
        for field in self._fields:
            objs.update(field.new_values.keys())
        return objs

    #
    # BaseEditorSlave
    #

    def confirm(self, dialog):
        marker('Saving data')

        objs = self.get_changed_objects()
        total = len(objs)
        for i, obj in enumerate(objs):
            for field in self._fields:
                field.save_value(obj)
                yield i, total
            # Flush soon, so that any errors triggered by database constraints
            # pop up.
            self._store.flush()

        marker('Done saving data')

    #
    #   Callbacks
    #

    def _on_field_combo__changed(self, combo):
        self._setup_editor(combo.get_selected())

    def _on_apply_button__clicked(self, button):
        self._apply()
コード例 #56
0
ファイル: search.py プロジェクト: hsavolai/vmlab
class NumberSearchFilter(SearchFilter):
    """
    A filter which helps you to search by a number interval.
    """
    __gtype_name__ = 'NumberSearchFilter'

    def __init__(self, label=''):
        """
        Create a new NumberSearchFilter object.
        @param label: name of the search filter
        """

        self._options = {}

        SearchFilter.__init__(self, label=label)
        self.title_label = gtk.Label(label)
        self.title_label.set_alignment(1.0, 0.5)
        self.pack_start(self.title_label, False, False)
        self.title_label.show()

        self.mode = ProxyComboBox()
        self.mode.connect('content-changed', self._on_mode__content_changed)
        self.pack_start(self.mode, False, False, 6)
        self.mode.show()

        self.start = gtk.SpinButton(climb_rate=1.0)
        self.start.get_adjustment().step_increment = 1.0
        self.start.set_range(-sys.maxint-1, sys.maxint)
        self.pack_start(self.start, False, False, 6)
        self.start.show()
        self.start.connect_after('activate', self._on_entry__activate)

        self.and_label = gtk.Label(_("And"))
        self.pack_start(self.and_label, False, False)
        self.and_label.show()

        self.end = gtk.SpinButton(climb_rate=1.0)
        self.end.get_adjustment().step_increment = 1.0
        self.end.set_range(-sys.maxint-1, sys.maxint)
        self.pack_start(self.end, False, False, 6)
        self.end.show()
        self.end.connect_after('activate', self._on_entry__activate)

        for option in (LowerThan, EqualsTo, GreaterThan, Between):
            self.add_option(option)

        self.mode.select_item_by_position(0)

    def set_digits(self, digits):
        """
        Number of decimal place to be displayed
        @param digits: number of decimal places
        """
        self.start.set_digits(digits)
        self.end.set_digits(digits)

    #
    #   Private
    #

    def _update_visibility(self):
        option = self.mode.get_selected_data()
        numbers = option.numbers
        if numbers == 0:
            self.start.hide()
            self.and_label.hide()
            self.end.hide()
        elif numbers == 1:
            self.start.show()
            self.and_label.hide()
            self.end.hide()
        elif numbers == 2:
            self.start.show()
            self.and_label.show()
            self.end.show()


    #
    #   Callbacks
    #

    def _on_entry__activate(self, entry):
        self.emit('changed')

    def _on_mode__content_changed(self, combo):
        self._update_visibility()
        self.emit('changed')

    #
    #   SearchFilter
    #

    def get_state(self):
        # Using Decimals for better precision.
        start_value = Decimal("%.2f" % self.start.get_value())
        end_value = Decimal("%.2f" % self.end.get_value())
        option = self.mode.get_selected_data()

        start, end = option().get_interval(start_value, end_value)
        return NumberIntervalQueryState(filter=self, start=start, end=end)

    def get_title_label(self):
        return self.title_label

    def get_mode_combo(self):
        return self.mode

    def get_description(self):
        desc = ''
        option = self.mode.get_selected_data()
        if option is not None:
            desc += option.name
            if option.numbers > 0:
                start = self.start.get_value_as_int()
                if option.numbers == 1:
                    desc += ' %d' % start
                elif option.numbers == 2:
                    end = self.end.get_value_as_int()
                    desc += ' %d %s %d' % (start, self.and_label.get_text(), end,)
        if desc:
            return '%s %s' % (self.get_title_label().get_text(), desc)

    #
    #   Public API
    #

    def add_option(self, option_type, position=-2):
        """
        Adds a date option
        @param option_type: option to add
        @type option_type: a L{NumberSearchOption} subclass
        """
        option = option_type()
        num = len(self.mode) + position
        self.mode.insert_item(num, option.name, option_type)
        self._options[option_type] = option
コード例 #57
0
ファイル: accounteditor.py プロジェクト: romaia/stoq
class AccountEditor(BaseEditor):
    """ Account Editor """
    gladefile = "AccountEditor"
    proxy_widgets = ['description', 'code']
    model_type = Account
    model_name = _('Account')

    def __init__(self, store, model=None, parent_account=None):
        self._last_account_type = None
        self._bank_number = -1
        self._bank_widgets = []
        self._bank_option_widgets = []
        self._option_fields = {}
        self._test_button = None
        self.existing = model is not None
        self.parent_account = parent_account
        self.bank_model = _TemporaryBankAccount()
        BaseEditor.__init__(self, store, model)

        action_area = self.main_dialog.action_area
        action_area.set_layout(gtk.BUTTONBOX_END)
        action_area.pack_start(self._test_button, expand=False, fill=False)
        action_area.set_child_secondary(self._test_button, True)
        self._test_button.show()

    #
    # BaseEditor hooks
    #

    def create_model(self, store):
        return Account(description=u"",
                       account_type=Account.TYPE_CASH,
                       store=store)

    def _setup_widgets(self):
        self._test_button = gtk.Button(_("Print a test bill"))
        self._test_button.connect('clicked',
                                  self._on_test_button__clicked)
        self.parent_accounts = AccountTree(with_code=False, create_mode=True)
        self.parent_accounts.connect('selection-changed',
                                     self._on_parent_accounts__selection_changed)
        self.tree_box.pack_start(self.parent_accounts)
        self.tree_box.reorder_child(self.parent_accounts, 0)

        if self.model == sysparam(self.store).IMBALANCE_ACCOUNT:
            self.account_type.set_sensitive(False)

        self.account_type.prefill(Account.account_type_descriptions)
        account_type = self.model.account_type

        self.parent_accounts.insert_initial(self.store,
                                            edited_account=self.model)
        if self.parent_account:
            account = self.parent_accounts.get_account_by_id(
                self.parent_account.id)
            self.parent_accounts.select(account)
            if not self.existing:
                account_type = account.account_type
        self.account_type.select(account_type)
        self.parent_accounts.show()

    def setup_proxies(self):
        self._setup_widgets()
        self.add_proxy(self.model, AccountEditor.proxy_widgets)

    def validate_confirm(self):
        if not self.model.description:
            return False
        account = self.parent_accounts.get_selected()
        if not account:
            return True
        return account.selectable

    def on_confirm(self):
        new_parent = self.parent_accounts.get_selected()
        if new_parent:
            new_parent = new_parent.account
        if new_parent != self.model:
            self.model.parent = new_parent
        self.model.account_type = self.account_type.get_selected()
        self._save_bank()

    def refresh_ok(self, value):
        BaseEditor.refresh_ok(self, value)

        account_type = self.account_type.get_selected()
        if account_type != Account.TYPE_BANK:
            value = False
        self._test_button.set_sensitive(value)

    # Private

    def _save_bank(self):
        bank_account = self.model.bank
        if not bank_account:
            bank_account = BankAccount(account=self.model,
                                       store=self.store)
        # FIXME: Who sets this to a str?
        bank_account.bank_account = unicode(self.bank_model.bank_account)
        bank_account.bank_branch = unicode(self.bank_model.bank_branch)
        if self._bank_number is not None:
            bank_account.bank_number = self.bank_model.bank_number

        self._save_bank_bill_options(bank_account)

    def _save_bank_bill_options(self, bank_account):
        for option, entry in self._option_fields.items():
            value = unicode(entry.get_text())
            bill_option = self.store.find(BillOption,
                                          bank_account=bank_account,
                                          option=option).one()
            if bill_option is None:
                bill_option = BillOption(store=self.store,
                                         bank_account=bank_account,
                                         option=option,
                                         value=value)
            bill_option.value = value

    def _add_widget(self, label, widget, options=False):
        n_rows = self.table.props.n_rows
        l = gtk.Label()
        l.set_markup(label)
        l.props.xalign = 1.0
        self.table.resize(n_rows + 1, 2)
        self.table.attach(
            l, 0, 1, n_rows, n_rows + 1,
            gtk.FILL, 0, 0, 0)
        self.table.attach(
            widget, 1, 2, n_rows, n_rows + 1,
            gtk.EXPAND | gtk.FILL, 0, 0, 0)
        if options:
            self._bank_option_widgets.extend([l, widget])
        else:
            self._bank_widgets.extend([l, widget])
        l.show()
        return l

    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)
                self._add_widget("<i>%s</i>:" % (api.escape(option.capitalize()), ),
                                 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 _fill_bank_account(self):
        if not self.model.bank:
            return

        self.bank_model.bank_branch = self.model.bank.bank_branch.encode('utf-8')
        self.bank_model.bank_account = self.model.bank.bank_account.encode('utf-8')
        self.bank_proxy.update('bank_branch')
        self.bank_proxy.update('bank_account')

        bill_options = list(self.store.find(BillOption,
                                            bank_account=self.model.bank))
        for bill_option in bill_options:
            if bill_option.option is None:
                continue
            field_entry = self._option_fields.get(bill_option.option)
            if field_entry:
                field_entry.set_text(bill_option.value)

    def _update_account_type(self, account_type):
        if not self.account_type.get_sensitive():
            return
        if account_type != Account.TYPE_BANK:
            self._remove_bank_widgets()
            self._remove_bank_option_widgets()
            self.code.set_sensitive(True)
            return

        self.code.set_sensitive(False)
        self.bank_type = ProxyComboBox()
        self._add_widget(api.escape(_("Bank:")), self.bank_type)
        self.bank_type.connect('content-changed',
                               self._on_bank_type__content_changed)
        self.bank_type.show()

        banks = [(_('Generic'), None)]
        banks.extend([(b.description,
                       b.bank_number) for b in get_all_banks()])
        self.bank_type.prefill(banks)

        if self.model.bank:
            try:
                self.bank_type.select(self.model.bank.bank_number)
            except KeyError:
                self.bank_type.select(None)

        self._update_bank_type()

    def _remove_bank_widgets(self):
        for widget in self._bank_widgets:
            widget.get_parent().remove(widget)
            widget.destroy()
        self.table.resize(5, 2)
        self._bank_widgets = []

    def _remove_bank_option_widgets(self):
        for widget in self._bank_option_widgets:
            widget.get_parent().remove(widget)
            widget.destroy()
        self.table.resize(5 + len(self._bank_widgets) / 2, 2)
        self._bank_option_widgets = []
        self._option_fields = {}

    def _print_test_bill(self):
        try:
            bank_info = get_bank_info_by_number(self.bank_model.bank_number)
        except NotImplementedError:
            info(_("This bank does not support printing of bills"))
            return
        kwargs = dict(
            valor_documento=12345.67,
            data_vencimento=datetime.date.today(),
            data_documento=datetime.date.today(),
            data_processamento=datetime.date.today(),
            nosso_numero=u'624533',
            numero_documento=u'1138',
            sacado=[_(u"Drawee"), _(u"Address"), _(u"Details")],
            cedente=_(u"Supplier"),
            demonstrativo=[_(u"Demonstration")],
            instrucoes=[_(u"Instructions")],
            agencia=self.bank_model.bank_branch,
            conta=self.bank_model.bank_account,
        )
        for opt in self.bank_model.options:
            kwargs[opt.option] = opt.value
        data = bank_info(**kwargs)
        print_report(BillTestReport, data)

    # Callbacks

    def _on_parent_accounts__selection_changed(self, objectlist, account):
        self.force_validation()

    def on_description__activate(self, entry):
        if self.validate_confirm():
            self.confirm()

    def on_description__validate(self, entry, text):
        if not text:
            return ValidationError(_("Account description cannot be empty"))

    def on_account_type__content_changed(self, account_type):
        account_type = account_type.get_selected()
        if self._last_account_type == account_type:
            return
        self._update_account_type(account_type)
        self._last_account_type = account_type

    def _on_bank_type__content_changed(self, bank_type):
        bank_number = bank_type.get_selected()
        if self._bank_number == bank_number:
            return
        self._update_bank_type()

        self._bank_number = bank_number

    def _on_bank_branch__validate(self, entry, value, bank_info):
        if bank_info:
            try:
                bank_info.validate_field(value)
            except BoletoException, e:
                return ValidationError(str(e))