class Diary(ProxyDelegate): def __init__(self): self.entries = ObjectList([ Column("title", width=120), Column("period", width=80), Column("text", expand=True) ]) ProxyDelegate.__init__(self, DiaryEntry(), ['title', 'period', 'text'], gladefile="diary.ui", delete_handler=self.quit_if_last) self.hbox.pack_start(self.entries, True, True, 0) self.entries.show() self.entries.grab_focus() def on_add__clicked(self, button): entry = DiaryEntry() entry.title = 'New title' self.set_model(entry) self.entries.append(entry) self.title.grab_focus() def on_remove__clicked(self, button): entry = self.entries.get_selected() if entry: self.entries.remove(entry) def on_entries__selection_changed(self, entries, instance): if instance: self.set_model(instance)
class Diary(ProxyDelegate): def __init__(self): self.entries = ObjectList([Column("title", width=120), Column("period", width=80), Column("text", expand=True)]) ProxyDelegate.__init__(self, DiaryEntry(), ['title', 'period', 'text'], gladefile="diary", delete_handler=self.quit_if_last) self.hbox.pack_start(self.entries) self.entries.show() self.entries.grab_focus() def on_add__clicked(self, button): entry = DiaryEntry() entry.title = 'New title' self.set_model(entry) self.entries.append(entry) self.title.grab_focus() def on_remove__clicked(self, button): entry = self.entries.get_selected() if entry: self.entries.remove(entry) def on_entries__selection_changed(self, entries, instance): if instance: self.set_model(instance)
class Diary(ProxyDelegate): def __init__(self): self.entries = ObjectList([ Column("title", width=120, sorted=True), Column("period", width=80), Column("text", expand=True, visible=False) ]) ProxyDelegate.__init__(self, DiaryEntry(), ['title', 'period', 'text', 'chars', 'words'], gladefile="diary2.ui", delete_handler=self.quit_if_last) self.hbox.pack_start(self.entries, True, True, 0) self.entries.show() self.entries.grab_focus() self.set_editable(False) def set_editable(self, editable): self.leftbox.set_sensitive(editable) self.remove.set_sensitive(editable) def proxy_updated(self, *args): self.entries.update(self.model) def on_add__clicked(self, button): entry = DiaryEntry() entry.title = 'Untitled' self.entries.append(entry, select=True) self.set_editable(True) def on_remove__clicked(self, button): entry = self.entries.get_selected() if entry: self.entries.remove(entry, select=True) self.set_editable(len(self.entries) >= 1) if not len(self.entries): self.set_model(None) def on_text__content_changed(self, text): self.proxy.update_many(("chars", "words")) self.entries.update(self.model) def on_entries__selection_changed(self, entries, instance): if instance: self.set_model(instance) self.title.grab_focus()
class Diary(ProxyDelegate): def __init__(self): self.entries = ObjectList([Column("title", width=120, sorted=True), Column("period", width=80), Column("text", expand=True, visible=False)]) ProxyDelegate.__init__(self, DiaryEntry(), ['title', 'period', 'text', 'chars', 'words'], gladefile="diary2.ui", delete_handler=self.quit_if_last) self.hbox.pack_start(self.entries, True, True, 0) self.entries.show() self.entries.grab_focus() self.set_editable(False) def set_editable(self, editable): self.leftbox.set_sensitive(editable) self.remove.set_sensitive(editable) def proxy_updated(self, *args): self.entries.update(self.model) def on_add__clicked(self, button): entry = DiaryEntry() entry.title = 'Untitled' self.entries.append(entry, select=True) self.set_editable(True) def on_remove__clicked(self, button): entry = self.entries.get_selected() if entry: self.entries.remove(entry, select=True) self.set_editable(len(self.entries) >= 1) if not len(self.entries): self.set_model(None) def on_text__content_changed(self, text): self.proxy.update_many(("chars", "words")) self.entries.update(self.model) def on_entries__selection_changed(self, entries, instance): if instance: self.set_model(instance) self.title.grab_focus()
class TestSignals(unittest.TestCase): def setUp(self): self.klist = ObjectList() self.klist.connect('has-rows', self._on_klist__has_rows) self.klist.connect('selection-changed', self._on_klist__selection_changed) self.rows = None self.selected = None def _on_klist__has_rows(self, klist, rows): self.rows = rows def _on_klist__selection_changed(self, klist, selected): self.selected = selected def testHasRows(self): self.assertEqual(self.rows, None) self.assertEqual(len(self.klist), 0) # Add one self.klist.append(0) self.assertEqual(len(self.klist), 1) self.assertEqual(self.rows, True) self.klist.remove(0) self.assertEqual(self.rows, False) self.assertEqual(len(self.klist), 0) # Add several self.klist.extend((1, 2)) self.assertEqual(len(self.klist), 2) self.assertEqual(self.rows, True) self.klist.remove(1) self.assertEqual(self.rows, True) self.klist.remove(2) self.assertEqual(self.rows, False) self.assertEqual(len(self.klist), 0) def testSelectionChanged(self): self.assertEqual(self.selected, None) self.assertEqual(len(self.klist), 0) self.klist.extend((0, 1)) self.klist.select(0) self.assertEqual(self.selected, 0) self.klist.unselect_all() self.assertEqual(self.selected, None) self.assertRaises(ValueError, self.klist.select, 2)
class ListContainer(gtk.HBox): """A ListContainer is an L{ObjectList} with buttons to be able to modify the content of the list. Depending on the list_mode, @see L{set_list_mode} you will have add, remove and edit buttons. Signals ======= - B{add-item} (returns item): - emitted when the add button is clicked, you're expected to return an object here - B{remove-item} (item, returns bool): - emitted when removing an item, you can block the removal from the list by returning False - B{edit-item} (item): - emitted when editing an item you can block the update afterwards by returning False @ivar add_button: add button @type add_button: L{gtk.Button} @ivar remove_button: remove button @type remove_button: L{gtk.Button} @ivar edit_button: edit button @type edit_button: L{gtk.Button} """ gsignal('add-item', retval=object) gsignal('remove-item', object, retval=bool) gsignal('edit-item', object, retval=bool) gsignal('selection-changed', object) def __init__(self, columns, orientation=gtk.ORIENTATION_VERTICAL): """ Create a new ListContainer object. @param columns: columns for the L{kiwi.ui.objectlist.ObjectList} @type columns: a list of L{kiwi.ui.objectlist.Columns} @param orientation: the position where the buttons will be placed: at the right (vertically) or at the bottom (horizontally) of the list. Defaults to the right of the list. @type: gtk.ORIENTATION_HORIZONTAL or gtk.ORIENTATION_VERTICAL """ self._list_type = None gtk.HBox.__init__(self) self._orientation = orientation self._create_ui(columns) self.set_list_type(ListType.NORMAL) # Private API def _create_ui(self, columns): self.list = ObjectList(columns) self.list.connect('selection-changed', self._on_list__selection_changed) self.list.connect('row-activated', self._on_list__row_activated) self.add_button = gtk.Button(stock=gtk.STOCK_ADD) self.add_button.connect('clicked', self._on_add_button__clicked) self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE) self.remove_button.set_sensitive(False) self.remove_button.connect('clicked', self._on_remove_button__clicked) self.edit_button = gtk.Button(stock=gtk.STOCK_EDIT) self.edit_button.set_sensitive(False) self.edit_button.connect('clicked', self._on_edit_button__clicked) self._vbox = gtk.VBox(spacing=6) if self._orientation == gtk.ORIENTATION_VERTICAL: self.pack_start(self.list) self.list.show() self._add_buttons_to_box(self._vbox) self._pack_vbox() elif self._orientation == gtk.ORIENTATION_HORIZONTAL: self._vbox.pack_start(self.list) self.list.show() hbox = gtk.HBox(spacing=6) self._add_buttons_to_box(hbox) self._vbox.pack_start(hbox, expand=False) hbox.show() self._pack_vbox() else: raise TypeError( "buttons_orientation must be gtk.ORIENTATION_VERTICAL " " or gtk.ORIENTATION_HORIZONTAL") def _add_buttons_to_box(self, box): box.pack_start(self.add_button, expand=False) box.pack_start(self.remove_button, expand=False) box.pack_start(self.edit_button, expand=False) def _pack_vbox(self): self.pack_start(self._vbox, expand=False, padding=6) self._vbox.show() def _set_child_packing(self, padding): expand = self._orientation == gtk.ORIENTATION_HORIZONTAL self.set_child_packing(self._vbox, expand, True, padding, gtk.PACK_START) def _add_item(self): retval = self.emit('add-item') if retval is None: return elif isinstance(retval, NotImplementedError): raise retval self.list.append(retval) def _remove_item(self, item): retval = self.emit('remove-item', item) if retval: self.list.remove(item) def _edit_item(self, item): retval = self.emit('edit-item', item) if retval: self.list.update(item) # Public API def add_item(self, item): """Appends an item to the list @param item: item to append """ self.list.append(item) def add_items(self, items): """Appends a list of items to the list @param items: items to add @type items: a sequence of items """ self.list.extend(items) def remove_item(self, item): """Removes an item from the list @param item: item to remove """ self.list.remove(item) def update_item(self, item): """Updates an item in the list. You should call this if you change the object @param item: item to update """ self.list.update(item) def default_remove(self, item): """Asks the user confirmation for removal of an item. @param item: a description of the item that will be removed @returns: True if the user confirm the removal, False otherwise """ response = yesno(_('Do you want to remove %s ?') % (quote(str(item)), ), parent=None, default=gtk.RESPONSE_OK, buttons=((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_REMOVE, gtk.RESPONSE_OK))) return response == gtk.RESPONSE_OK def set_list_type(self, list_type): """Sets the kind of list type. @param list_type: """ if not isinstance(list_type, ListType): raise TypeError("list_type must be a ListType enum") self.add_button.set_property('visible', (list_type != ListType.READONLY and list_type != ListType.REMOVEONLY and list_type != ListType.UNADDABLE)) self.remove_button.set_property( 'visible', (list_type != ListType.READONLY and list_type != ListType.UNREMOVABLE)) self.edit_button.set_property('visible', (list_type != ListType.READONLY and list_type != ListType.UNEDITABLE and list_type != ListType.REMOVEONLY)) if list_type in [ListType.READONLY, ListType.REMOVEONLY]: padding = 0 else: padding = 6 self._set_child_packing(padding) self._list_type = list_type def clear(self): """Removes all the items in the list""" self.list.clear() # Callbacks def _on_list__selection_changed(self, list, selection): object_selected = selection is not None self.remove_button.set_sensitive(object_selected) self.edit_button.set_sensitive(object_selected) self.emit('selection-changed', selection) def _on_list__row_activated(self, list, item): if (self._list_type != ListType.READONLY and self._list_type != ListType.UNEDITABLE): self._edit_item(item) def _on_add_button__clicked(self, button): self._add_item() def _on_remove_button__clicked(self, button): self._remove_item(self.list.get_selected()) def _on_edit_button__clicked(self, button): self._edit_item(self.list.get_selected())
class ListContainer(gtk.HBox): """A ListContainer is an L{ObjectList} with buttons to be able to modify the content of the list. Depending on the list_mode, @see L{set_list_mode} you will have add, remove and edit buttons. Signals ======= - B{add-item} (returns item): - emitted when the add button is clicked, you're expected to return an object here - B{remove-item} (item, returns bool): - emitted when removing an item, you can block the removal from the list by returning False - B{edit-item} (item): - emitted when editing an item you can block the update afterwards by returning False @ivar add_button: add button @type add_button: L{gtk.Button} @ivar remove_button: remove button @type remove_button: L{gtk.Button} @ivar edit_button: edit button @type edit_button: L{gtk.Button} """ gsignal('add-item', retval=object) gsignal('remove-item', object, retval=bool) gsignal('edit-item', object, retval=bool) gsignal('selection-changed', object) def __init__(self, columns, orientation=gtk.ORIENTATION_VERTICAL): """ Create a new ListContainer object. @param columns: columns for the L{kiwi.ui.objectlist.ObjectList} @type columns: a list of L{kiwi.ui.objectlist.Columns} @param orientation: the position where the buttons will be placed: at the right (vertically) or at the bottom (horizontally) of the list. Defaults to the right of the list. @type: gtk.ORIENTATION_HORIZONTAL or gtk.ORIENTATION_VERTICAL """ self._list_type = None gtk.HBox.__init__(self) self._orientation = orientation self._create_ui(columns) self.set_list_type(ListType.NORMAL) # Private API def _create_ui(self, columns): self.list = ObjectList(columns) self.list.connect('selection-changed', self._on_list__selection_changed) self.list.connect('row-activated', self._on_list__row_activated) self.add_button = gtk.Button(stock=gtk.STOCK_ADD) self.add_button.connect('clicked', self._on_add_button__clicked) self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE) self.remove_button.set_sensitive(False) self.remove_button.connect('clicked', self._on_remove_button__clicked) self.edit_button = gtk.Button(stock=gtk.STOCK_EDIT) self.edit_button.set_sensitive(False) self.edit_button.connect('clicked', self._on_edit_button__clicked) self._vbox = gtk.VBox(spacing=6) if self._orientation == gtk.ORIENTATION_VERTICAL: self.pack_start(self.list) self.list.show() self._add_buttons_to_box(self._vbox) self._pack_vbox() elif self._orientation == gtk.ORIENTATION_HORIZONTAL: self._vbox.pack_start(self.list) self.list.show() hbox = gtk.HBox(spacing=6) self._add_buttons_to_box(hbox) self._vbox.pack_start(hbox, expand=False) hbox.show() self._pack_vbox() else: raise TypeError( "buttons_orientation must be gtk.ORIENTATION_VERTICAL " " or gtk.ORIENTATION_HORIZONTAL") def _add_buttons_to_box(self, box): box.pack_start(self.add_button, expand=False) box.pack_start(self.remove_button, expand=False) box.pack_start(self.edit_button, expand=False) def _pack_vbox(self): self.pack_start(self._vbox, expand=False, padding=6) self._vbox.show() def _set_child_packing(self, padding): expand = self._orientation == gtk.ORIENTATION_HORIZONTAL self.set_child_packing(self._vbox, expand, True, padding, gtk.PACK_START) def _add_item(self): retval = self.emit('add-item') if retval is None: return elif isinstance(retval, NotImplementedError): raise retval self.list.append(retval) def _remove_item(self, item): retval = self.emit('remove-item', item) if retval: self.list.remove(item) def _edit_item(self, item): retval = self.emit('edit-item', item) if retval: self.list.update(item) # Public API def add_item(self, item): """Appends an item to the list @param item: item to append """ self.list.append(item) def add_items(self, items): """Appends a list of items to the list @param items: items to add @type items: a sequence of items """ self.list.extend(items) def remove_item(self, item): """Removes an item from the list @param item: item to remove """ self.list.remove(item) def update_item(self, item): """Updates an item in the list. You should call this if you change the object @param item: item to update """ self.list.update(item) def default_remove(self, item): """Asks the user confirmation for removal of an item. @param item: a description of the item that will be removed @returns: True if the user confirm the removal, False otherwise """ response = yesno(_('Do you want to remove %s ?') % (quote(str(item)),), parent=None, default=gtk.RESPONSE_OK, buttons=((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_REMOVE, gtk.RESPONSE_OK))) return response == gtk.RESPONSE_OK def set_list_type(self, list_type): """Sets the kind of list type. @param list_type: """ if not isinstance(list_type, ListType): raise TypeError("list_type must be a ListType enum") self.add_button.set_property( 'visible', (list_type != ListType.READONLY and list_type != ListType.REMOVEONLY and list_type != ListType.UNADDABLE)) self.remove_button.set_property( 'visible', (list_type != ListType.READONLY and list_type != ListType.UNREMOVABLE)) self.edit_button.set_property( 'visible', (list_type != ListType.READONLY and list_type != ListType.UNEDITABLE and list_type != ListType.REMOVEONLY)) if list_type in [ListType.READONLY, ListType.REMOVEONLY]: padding = 0 else: padding = 6 self._set_child_packing(padding) self._list_type = list_type def clear(self): """Removes all the items in the list""" self.list.clear() # Callbacks def _on_list__selection_changed(self, list, selection): object_selected = selection is not None self.remove_button.set_sensitive(object_selected) self.edit_button.set_sensitive(object_selected) self.emit('selection-changed', selection) def _on_list__row_activated(self, list, item): if (self._list_type != ListType.READONLY and self._list_type != ListType.UNEDITABLE): self._edit_item(item) def _on_add_button__clicked(self, button): self._add_item() def _on_remove_button__clicked(self, button): self._remove_item(self.list.get_selected()) def _on_edit_button__clicked(self, button): self._edit_item(self.list.get_selected())
class ChecklistView(PidaView): key = 'checklist.view' icon_name = 'gtk-todo' label_text = _('Check list') def create_ui(self): self._vbox = gtk.VBox(spacing=3) self._vbox.set_border_width(3) self.create_toolbar() self.create_newitem() self.create_list() self.add_main_widget(self._vbox) self._vbox.show_all() def create_tab_label(self, icon_name, text): if None in [icon_name, text]: return None label = gtk.Label(text) b_factory = gtk.HBox b = b_factory(spacing=2) icon = gtk.image_new_from_stock(icon_name, gtk.ICON_SIZE_MENU) b.pack_start(icon) b.pack_start(label) b.show_all() return b def create_list(self): self._list = ObjectList([ Column('done', title=_('Done'), data_type=bool, editable=True), Column('title', title=_('Title'), data_type=str, editable=True, expand=True), Column('priority', title=_('Priority'), data_type=ChecklistStatus, editable=True) ]) self._list.connect('cell-edited', self._on_item_edit) self._list.connect('selection-changed', self._on_item_selected) self._list.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self._vbox.add(self._list) self._sort_combo = AttrSortCombo(self._list, [ ('done', _('Done')), ('title', _('Title')), ('priority', _('Priority')), ], 'title') self._vbox.pack_start(self._sort_combo, expand=False) self._list.show_all() self._sort_combo.show_all() def create_newitem(self): self._hbox = gtk.HBox(spacing=3) self._newitem_title = gtk.Entry() self._newitem_title.connect('changed', self._on_newitem_changed) self._newitem_ok = gtk.Button(stock=gtk.STOCK_ADD) self._newitem_ok.connect('clicked', self._on_item_add) self._newitem_ok.set_sensitive(False) self._hbox.pack_start(self._newitem_title, expand=True) self._hbox.pack_start(self._newitem_ok, expand=False) self._vbox.pack_start(self._hbox, expand=False) self._hbox.show_all() def create_toolbar(self): self._uim = gtk.UIManager() self._uim.insert_action_group(self.svc.get_action_group(), 0) uim_data = pkgutil.get_data(__name__, 'uidef/checklist-toolbar.xml') self._uim.add_ui_from_string(uim_data) self._uim.ensure_update() self._toolbar = self._uim.get_toplevels('toolbar')[0] self._toolbar.set_style(gtk.TOOLBAR_ICONS) self._toolbar.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR) self._vbox.pack_start(self._toolbar, expand=False) self.svc.get_action('checklist_del').set_sensitive(False) self._toolbar.show_all() def add_item(self, item): self._list.append(item, select=True) self.svc.save() def update_item(self, item): self._list.update(item) self.svc.save() def remove_item(self, item): self._list.remove(item) self.svc.save() def clear(self): self._list.clear() def _on_item_selected(self, olist, item): self.svc.get_action('checklist_del').set_sensitive(item is not None) self.svc.set_current(item) def _on_item_edit(self, olist, item, value): self.svc.save() def _on_item_add(self, w): title = self._newitem_title.get_text() self.svc.add_item(ChecklistItem(title=title)) self._newitem_title.set_text('') def _on_newitem_changed(self, w): self._newitem_ok.set_sensitive(self._newitem_title.get_text() != '') def can_be_closed(self): self.svc.get_action('show_checklist').set_active(False)
class DataTests(unittest.TestCase): """In all this tests we use the same configuration for a list""" def setUp(self): self.win = gtk.Window() self.win.set_default_size(400, 400) self.list = ObjectList([Column('name'), Column('age')]) self.win.add(self.list) refresh_gui() def tearDown(self): self.win.destroy() del self.win def testAddingOneInstance(self): # we should have two columns now self.assertEqual(2, len(self.list.get_columns())) person = Person('henrique', 21) self.list.append(person) refresh_gui() # usually you don't use the model directly, but tests are all about # breaking APIs, right? self.assertEqual(self.list[0], person) self.assertEqual(self.list[0].name, 'henrique') self.assertEqual(self.list[0].age, 21) # we still have to columns, right? self.assertEqual(2, len(self.list.get_columns())) def testAddingAObjectList(self): global persons self.list.add_list(persons) refresh_gui() self.assertEqual(len(self.list), len(persons)) def testAddingABunchOfInstances(self): global persons for person in persons: self.list.append(person) refresh_gui() self.assertEqual(len(self.list), len(persons)) def testRemovingOneInstance(self): global persons self.list.add_list(persons) refresh_gui() # we are going to remove Kiko person = persons[2] self.list.remove(person) self.assertEqual(len(self.list), len(persons) - 1) # now let's remove something that is not on the list #new_person = Person('Evandro', 24) #self.assertRaises(ValueError, self.list.remove, new_person) # note that even a new person with the same values as a person # in the list is not considered to be in the list #existing_person = Person('Gustavo', 25) #self.assertRaises(ValueError, self.list.remove, # existing_person) def testClearObjectList(self): global persons self.list.add_list(persons) refresh_gui() self.list.clear() self.assertEqual(len(self.list), 0) def testUpdatingOneInstance(self): global persons self.list.add_list(persons) refresh_gui() persons[0].age = 29 self.list.update(persons[0]) refresh_gui() # Do we have the same number of instances that we had before ? self.assertEqual(len(self.list), len(persons)) # Trying to find our updated instance in the list self.assertEqual(self.list[0].age, 29) # let's be evil new_person = Person('Nando', 32) self.assertRaises(ValueError, self.list.update, new_person) def testContains(self): global persons self.list.add_list(persons) self.assertEqual(persons[0] in self.list, True) new_person = Person('Nando', 32) self.assertEqual(new_person in self.list, False) def testSelect(self): first = persons[0] self.list.add_list(persons) self.list.select(first) self.assertEqual(self.list.get_selected(), first) self.list.remove(first) self.assertRaises(ValueError, self.list.select, first)
class ListDialog: """ Diálogo de edição de uma tabela com botões padrão e uma lista de campos. """ def __init__(self, controle, tabela, titulo): """ controle é um objeto da classe Controle. tabela é o nome de uma instancia de Classe no Controle que referencia um tabela no Modelo. titulo é nome de leitura da tabela sendo editada (ex. 'Categorias') """ self.controle = controle self.tabela = tabela self.data = [] self.buttons = [] self.new_method = self.create_new_record self.save_method = self.salvar self.populate_method = self.populate self.titulo = titulo or self.tabela.nome_tabela self.edit_mode = False self.editing_new = False self.editing = False self.selection = None self.do_nothing = False def make_widget(self, fields, custom_buttons = []): """ Cria e retorna o widget que contém o toolbar, a lista e os campos para edição. fields é uma lista de FieldType. custom_buttons é uma lista de ListToolButton que substitui os botões padrão. """ #-------Campos self.fields = [] for field in fields: if field.show_field: field.label = gtk.Label(field.titulo + ":") if field.tabelacombo: field.entry = ComboEntry() tabelacombo = getattr(self.controle, field.tabelacombo) itens = tabelacombo.combo() field.entry.prefill(itens) else: field.entry = ProxyEntry(field.tipo) field.entry.set_mask(field.mask) self.fields.append(field) vbox_main = gtk.VBox() hbox_topo = gtk.HBox() self.widget = gtk.EventBox() #-------Toolbar toolbar = gtk.Toolbar() toolbar.set_orientation(gtk.ORIENTATION_VERTICAL) toolbar.set_style(gtk.TOOLBAR_BOTH) if not custom_buttons: self.tb_novo = ListToolButton(self.default_new, gtk.STOCK_NEW) self.tb_edit = ListToolButton(self.default_edit, gtk.STOCK_EDIT) self.custom_buttons = [self.tb_novo, self.tb_edit] else: self.custom_buttons = custom_buttons for tool_button in self.custom_buttons: toolbar.insert(tool_button.button, -1) #-------Lista vbox_lista = gtk.VBox() hbox_entry = gtk.HBox() self.entry_localizar = gtk.Entry() self.entry_localizar.connect('activate', self.localizar) label = gtk.Label('Localizar') frame_lista = gtk.Frame(self.titulo) self.listview = self.create_list() self.listview.connect("row_activated", self.on_row_activated) self.listview.connect('selection-changed',self.on_selection_changed) #-------Frame frame_dados = gtk.Frame("Informações") hbox_dados = gtk.HBox(False, 6) vbox_label = gtk.VBox(True, 4) vbox_entry = gtk.VBox(True, 4) for field in self.fields: if field.show_field: vbox_label.pack_start(field.label, False, True, 8) vbox_entry.pack_start(field.entry, False, True, 8) #Botões self.button_save = gtk.Button(stock=gtk.STOCK_SAVE) self.button_save.connect("clicked", self.save_method) self.button_cancel = gtk.Button(stock=gtk.STOCK_CANCEL) self.button_cancel.connect("clicked", self.cancel) vbox_dados_buttons = gtk.VButtonBox() vbox_dados_buttons.set_layout(gtk.BUTTONBOX_SPREAD) vbox_dados_buttons.add(self.button_save) vbox_dados_buttons.add(self.button_cancel) #-------Notify self.notify = self.controle.notify() self.notify_box = self.notify.get_widget() self.notify.show_notify('info','Clique em NOVO para adicionar um novo item') self.tabela.set_notify(self.notify) #-------Posicionar todos frame_lista.add(self.listview) vbox_lista.pack_start(hbox_entry, False, False, 2) vbox_lista.pack_start(frame_lista, True, True, 2) hbox_entry.pack_end(self.entry_localizar, False, False, 2) hbox_entry.pack_end(label, False, False, 2) hbox_topo.pack_start(toolbar, False, False, 5) hbox_topo.pack_start(vbox_lista, True, True, 2) hbox_dados.pack_start(vbox_label, False, False, 2) hbox_dados.pack_start(vbox_entry, True, True, 2) hbox_dados.pack_start(vbox_dados_buttons, False, False, 2) frame_dados.add(hbox_dados) vbox_main.pack_start(hbox_topo, True, True, 2) vbox_main.pack_start(frame_dados, False, False, 2) vbox_main.pack_start(self.notify_box, False, True, 2) self.widget.add(vbox_main) self.set_edit_mode(False) return self.widget def create_list(self): columns = [] for field in self.fields: if field.show_in_list: columns.append(Column(field.field_name, data_type = field.tipo, title = field.titulo)) self.lista = ObjectList(columns) self.data = self.populate_method() self.lista.extend(self.data) return self.lista def localizar(self, entry): text = self.entry_localizar.get_text().lower() searches = text.split(" ") if not searches: #lista vazia lista = self.data else: lista = [] for item in self.data: itemtext = "" #reúne o texto inteiro do item (separado por espaço): for field in self.fields: if field.searchable: itemtext += str(getattr(item, field.field_name)).lower() + " " contain_all = True for searchtext in searches: if searchtext not in itemtext: contain_all = False if contain_all: lista.append(item) self.lista.add_list(lista) def set_edit_mode(self, edit_mode): """ Coloca ou tira os campos em modo de edição. """ for field in self.fields: if field.entry: field.entry.set_sensitive(edit_mode) for tool_button in self.custom_buttons: tool_button.button.set_sensitive(not edit_mode) self.entry_localizar.set_sensitive(not edit_mode) self.button_save.set_sensitive(edit_mode) self.button_cancel.set_sensitive(edit_mode) self.editing = edit_mode def cancel(self, widget): """Cancela a edição de um item""" self.set_edit_mode(False) self.clear_entry() self.lista.refresh() if self.editing_new: self.lista.remove(self.newobj) self.editing_new = False self.notify.show_notify('info','Clique em NOVO para adicionar um novo item') def create_new_record(self): """Adiciona um item padrão a lista para depois ser editado""" self.notify.hide() obj = ListItem() for field in self.fields: if field.tipo == str or field.tabelacombo: setattr(obj, field.field_name, '') else: setattr(obj, field.field_name, converter.from_string(field.tipo, '0')) return obj def populate(self): """Popula a lista com os itens""" itens = self.tabela.listar() objetos = [] for item in itens: obj = ListItem() for field in self.fields: if not field.tabelacombo: setattr(obj, field.field_name, item[field.field_name]) else: tabelacombo = getattr(self.controle, field.tabelacombo) descricao = tabelacombo.item_descricao(item[field.field_name]) try: setattr(obj, field.field_name, descricao[0][0]) except: setattr(obj, field.field_name, descricao) objetos.append(obj) return objetos def default_new(self, sender): self.newobj = self.new_method() #Chama new_method para criar um novo item self.data.append(self.newobj) self.listview.append(self.newobj) self.listview.refresh() self.listview.select(self.newobj) self.set_edit_mode(True) self.editing_new = True self.item = self.selection def default_edit(self, sender): if self.selection: self.populate_entry(self.selection) self.set_edit_mode(True) self.item = self.selection def on_row_activated(self, list, item): """Preenche os campos com os valores da coluna clicada e coloca em modo de edição""" self.item = item self.populate_entry(item) def populate_entry(self, item): """Preenche os campos com os itens""" self.notify.hide() for field in self.fields: if field.entry: if field.tabelacombo: field.entry.select_item_by_label(str(getattr(item, field.field_name))) else: field.entry.set_text(str(getattr(item, field.field_name))) self.set_edit_mode(True) def clear_entry(self): """Limpa os campos apos edicao ou cancelar""" for field in self.fields: if field.entry: field.entry.set_text('') self.set_edit_mode(False) def on_selection_changed(self, list, selection): """Verifica se o usuario editou os campos e não salvou""" if self.do_nothing: self.do_nothing = False return self.selection = selection response = False if self.editing == True: for field in self.fields: if field.entry: if not field.identificador: user_edited = field.entry.get_text() #Se for um novo item if self.editing_new == True: if user_edited: response = self.ask_to_save(field) if response == True: self.salvar(None) else: self.cancel(None) else: if response: self.do_nothing = True self.listview.select(self.item) else: self.cancel(None) #Se editando item da lista elif self.editing == True: field_in_list = (str(getattr(self.item, field.field_name))) if user_edited != field_in_list: response = self.ask_to_save(field) if response == True: self.salvar(None) else: self.cancel(None) else: if response: self.do_nothing = True self.listview.select(self.item) def ask_to_save(self, field): """Pergunta ao usuario sobre a edicao de campos""" #Criando um novo if self.editing_new : question =str('Deseja salvar %s ?') for field in self.fields: if field.searchable: registro = quote(str(field.entry.get_text())) #Editando else: question =str('Deseja salvar alterações em %s ?') registro = quote(str(getattr(self.item, field.field_name))) response = yesno((question) % (registro,), parent=None, default=gtk.RESPONSE_OK, buttons=((gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), (gtk.STOCK_SAVE, gtk.RESPONSE_OK))) return response == gtk.RESPONSE_OK def salvar(self, widget): """Insere ou edita um registro na tabela""" record = {} #Insere novo if self.editing_new : record = self.tabela.insert(self.fields) if record : for field in self.fields: if field.identificador: setattr(self.newobj, field.field_name, record['last_id']) elif field.tabelacombo: tabelacombo = getattr(self.controle, field.tabelacombo) descricao = tabelacombo.item_descricao(record[field.field_name]) setattr(self.newobj, field.field_name, descricao[0][0]) else: setattr(self.newobj, field.field_name, record[field.field_name]) self.editing_new = False self.lista.refresh() self.clear_entry() self.hide_notify() #Edita else: record = self.tabela.update(self.fields, self.item) if record: for field in self.fields: if field.identificador: pass elif field.tabelacombo: tabelacombo = getattr(self.controle, field.tabelacombo) descricao = tabelacombo.item_descricao(record[field.field_name]) try: setattr(self.item, field.field_name, descricao[0][0]) except: setattr(self.item, field.field_name, descricao) else: setattr(self.item, field.field_name, record[field.field_name]) self.lista.refresh() self.clear_entry() self.hide_notify() def hide_notify(self): self.notify.hide()
class DataTests(unittest.TestCase): """In all this tests we use the same configuration for a list""" def setUp(self): self.win = Gtk.Window() self.win.set_default_size(400, 400) self.list = ObjectList([Column('name'), Column('age')]) self.win.add(self.list) refresh_gui() def tearDown(self): self.win.destroy() del self.win def testAddingOneInstance(self): # we should have two columns now self.assertEqual(2, len(self.list.get_columns())) person = Person('henrique', 21) self.list.append(person) refresh_gui() # usually you don't use the model directly, but tests are all about # breaking APIs, right? self.assertEqual(self.list[0], person) self.assertEqual(self.list[0].name, 'henrique') self.assertEqual(self.list[0].age, 21) # we still have to columns, right? self.assertEqual(2, len(self.list.get_columns())) def testAddingAObjectList(self): global persons self.list.add_list(persons) refresh_gui() self.assertEqual(len(self.list), len(persons)) def testAddingABunchOfInstances(self): global persons for person in persons: self.list.append(person) refresh_gui() self.assertEqual(len(self.list), len(persons)) def testRemovingOneInstance(self): global persons self.list.add_list(persons) refresh_gui() # we are going to remove Kiko person = persons[2] self.list.remove(person) self.assertEqual(len(self.list), len(persons) - 1) # now let's remove something that is not on the list #new_person = Person('Evandro', 24) #self.assertRaises(ValueError, self.list.remove, new_person) # note that even a new person with the same values as a person # in the list is not considered to be in the list #existing_person = Person('Gustavo', 25) #self.assertRaises(ValueError, self.list.remove, # existing_person) def testClearObjectList(self): global persons self.list.add_list(persons) refresh_gui() self.list.clear() self.assertEqual(len(self.list), 0) def testUpdatingOneInstance(self): global persons self.list.add_list(persons) refresh_gui() persons[0].age = 29 self.list.update(persons[0]) refresh_gui() # Do we have the same number of instances that we had before ? self.assertEqual(len(self.list), len(persons)) # Trying to find our updated instance in the list self.assertEqual(self.list[0].age, 29) # let's be evil new_person = Person('Nando', 32) self.assertRaises(ValueError, self.list.update, new_person) def testContains(self): global persons self.list.add_list(persons) self.assertEqual(persons[0] in self.list, True) new_person = Person('Nando', 32) self.assertEqual(new_person in self.list, False) def testSelect(self): first = persons[0] self.list.add_list(persons) self.list.select(first) self.assertEqual(self.list.get_selected(), first) self.list.remove(first) self.assertRaises(ValueError, self.list.select, first)
class MethodTest(unittest.TestCase): def setUp(self): self.klist = ObjectList([Column('name', sorted=True)], [Settable(name='first')]) def testNonZero(self): self.assertEqual(self.klist.__nonzero__(), True) self.klist.remove(self.klist[0]) self.assertEqual(self.klist.__nonzero__(), True) if not self.klist: raise AssertionError def testIter(self): for item1 in self.klist: pass for item2 in iter(self.klist): self.assertEqual(item1, item2) def testGetItem(self): self.klist.append(Settable(name='second')) model = self.klist.get_model() item1 = model[0][0] item2 = model[1][0] self.assertEqual(self.klist[0], item1) self.assertEqual(self.klist[:1], [item1]) self.assertEqual(self.klist[-1:], [item2]) self.assertRaises(TypeError, self.klist.__getitem__, None) def testSetItem(self): self.klist[0] = Settable(name='second') self.assertRaises(NotImplementedError, self.klist.__setitem__, slice(0), None) self.assertRaises(TypeError, self.klist.__setitem__, None, None) def testIndex(self): self.assertRaises(NotImplementedError, self.klist.index, 0, start=0) self.assertRaises(NotImplementedError, self.klist.index, 0, stop=0) self.assertEqual(self.klist.index(self.klist[0]), 0) self.assertRaises(ValueError, self.klist.index, None) def testCount(self): item = self.klist[0] self.assertEqual(self.klist.count(item), 1) self.klist.append(item) self.assertEqual(self.klist.count(item), 2) self.klist.clear() self.assertEqual(self.klist.count(item), 0) def testPop(self): self.assertRaises(NotImplementedError, self.klist.pop, None) def testReverse(self): self.assertRaises(NotImplementedError, self.klist.reverse, 1, 2) def testSort(self): self.assertRaises(NotImplementedError, self.klist.sort, 1, 2) def testSelectPath(self): self.klist.get_treeview().get_selection().set_mode( Gtk.SelectionMode.NONE) self.assertRaises(TypeError, self.klist.select_paths, (0, )) self.klist.get_treeview().get_selection().set_mode( Gtk.SelectionMode.SINGLE) self.klist.select_paths((0, )) def testSelect(self): self.klist.get_treeview().get_selection().set_mode( Gtk.SelectionMode.NONE) self.assertRaises(TypeError, self.klist.select, None) self.klist.get_treeview().get_selection().set_mode( Gtk.SelectionMode.SINGLE) def testGetSelected(self): item = self.klist[0] self.klist.select(item) self.klist.get_treeview().get_selection().set_mode( Gtk.SelectionMode.SINGLE) self.assertEqual(self.klist.get_selected(), item) def testGetSelectedRows(self): self.klist.get_treeview().get_selection().set_mode( Gtk.SelectionMode.MULTIPLE) item = self.klist[0] self.klist.select(item) self.assertEqual(self.klist.get_selected_rows(), [item]) def testGetNextAndPrevious(self): self.klist.append(Settable(name='second')) self.klist.append(Settable(name='third')) item1, item2, item3 = self.klist self.assertEqual(self.klist.get_next(item1), item2) self.assertEqual(self.klist.get_next(item2), item3) self.assertEqual(self.klist.get_next(item3), item1) self.assertRaises(ValueError, self.klist.get_next, None) self.assertEqual(self.klist.get_previous(item1), item3) self.assertEqual(self.klist.get_previous(item2), item1) self.assertEqual(self.klist.get_previous(item3), item2) self.assertRaises(ValueError, self.klist.get_previous, None) def testInsert(self): self.klist = ObjectList([Column('name')]) self.assertEqual(list(self.klist), []) self.klist.insert(0, Settable(name='one')) self.assertEqual(self.klist[0].name, 'one') self.klist.insert(0, Settable(name='two')) self.assertEqual(self.klist[0].name, 'two') self.assertEqual(self.klist[1].name, 'one') self.klist.insert(1, Settable(name='three')) self.assertEqual(self.klist[0].name, 'two') self.assertEqual(self.klist[1].name, 'three') self.assertEqual(self.klist[2].name, 'one')
class ListContainer(Gtk.Box): """A ListContainer is an :class:`ObjectList` with buttons to be able to modify the content of the list. Depending on the list_mode, @see :class:`set_list_mode` you will have add, remove and edit buttons. Signals ======= - B{add-item} (returns item): - emitted when the add button is clicked, you're expected to return an object here - B{remove-item} (item, returns bool): - emitted when removing an item, you can block the removal from the list by returning False - B{edit-item} (item): - emitted when editing an item you can block the update afterwards by returning False :ivar add_button: add button :type add_button: :class:`Gtk.Button` :ivar remove_button: remove button :type remove_button: :class:`Gtk.Button` :ivar edit_button: edit button :type edit_button: :class:`Gtk.Button` """ __gtype_name__ = 'ListContainer' gsignal('add-item', retval=object) gsignal('remove-item', object, retval=bool) gsignal('edit-item', object, retval=bool) gsignal('selection-changed', object) def __init__(self, columns, orientation=Gtk.Orientation.VERTICAL): """ Create a new ListContainer object. :param columns: columns for the :class:`kiwi.ui.objectlist.ObjectList` :type columns: a list of :class:`kiwi.ui.objectlist.Columns` :param orientation: the position where the buttons will be placed: at the right (vertically) or at the bottom (horizontally) of the list. Defaults to the right of the list. :type: Gtk.Orientation.HORIZONTAL or Gtk.Orientation.VERTICAL """ self._list_type = None super(ListContainer, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) self._orientation = orientation self._create_ui(columns) self.set_list_type(ListType.NORMAL) # Private API def _create_ui(self, columns): self.list = ObjectList(columns) self.list.connect('selection-changed', self._on_list__selection_changed) self.list.connect('row-activated', self._on_list__row_activated) self.add_button = Gtk.Button(stock=Gtk.STOCK_ADD) self.add_button.connect('clicked', self._on_add_button__clicked) self.remove_button = Gtk.Button(stock=Gtk.STOCK_REMOVE) self.remove_button.set_sensitive(False) self.remove_button.connect('clicked', self._on_remove_button__clicked) self.edit_button = Gtk.Button(stock=Gtk.STOCK_EDIT) self.edit_button.set_sensitive(False) self.edit_button.connect('clicked', self._on_edit_button__clicked) self._vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) if self._orientation == Gtk.Orientation.VERTICAL: self.pack_start(self.list, True, True, 0) self.list.show() self._add_buttons_to_box(self._vbox) self._pack_vbox() elif self._orientation == Gtk.Orientation.HORIZONTAL: self._vbox.pack_start(self.list, True, True, 0) self.list.show() hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) self._add_buttons_to_box(hbox) self._vbox.pack_start(hbox, False, True, 0) hbox.show() self._pack_vbox() else: raise TypeError( "buttons_orientation must be Gtk.Orientation.VERTICAL " " or Gtk.Orientation.HORIZONTAL") def _add_buttons_to_box(self, box): box.pack_start(self.add_button, False, True, 0) box.pack_start(self.remove_button, False, True, 0) box.pack_start(self.edit_button, False, True, 0) def _pack_vbox(self): self.pack_start(self._vbox, False, True, 6) self._vbox.show() def _set_child_packing(self, padding): expand = self._orientation == Gtk.Orientation.HORIZONTAL self.set_child_packing(self._vbox, expand, True, padding, Gtk.PackType.START) def _add_item(self): retval = self.emit('add-item') if retval is None: return elif isinstance(retval, NotImplementedError): raise retval self.list.append(retval) self.list.refresh() def _remove_item(self, item): retval = self.emit('remove-item', item) if retval: self.list.remove(item) def _edit_item(self, item): retval = self.emit('edit-item', item) if retval: self.list.update(item) # Public API def add_item(self, item): """Appends an item to the list :param item: item to append """ self.list.append(item) def add_items(self, items): """Appends a list of items to the list :param items: items to add :type items: a sequence of items """ self.list.extend(items) def remove_item(self, item): """Removes an item from the list :param item: item to remove """ self.list.remove(item) def update_item(self, item): """Updates an item in the list. You should call this if you change the object :param item: item to update """ self.list.update(item) def default_remove(self, item): """Asks the user confirmation for removal of an item. :param item: a description of the item that will be removed :returns: True if the user confirm the removal, False otherwise """ response = yesno(_('Do you want to remove %s ?') % (GLib.markup_escape_text(str(item)),), parent=None, default=Gtk.ResponseType.OK, buttons=((Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL), (Gtk.STOCK_REMOVE, Gtk.ResponseType.OK))) return response == Gtk.ResponseType.OK def set_list_type(self, list_type): """Sets the kind of list type. :param list_type: """ if not isinstance(list_type, ListType): raise TypeError("list_type must be a ListType enum") self.add_button.set_property( 'visible', list_type not in [ListType.READONLY, ListType.REMOVEONLY, ListType.UNADDABLE]) self.remove_button.set_property( 'visible', list_type not in [ListType.READONLY, ListType.ADDONLY, ListType.UNREMOVABLE]) self.edit_button.set_property( 'visible', list_type not in [ListType.READONLY, ListType.ADDONLY, ListType.UNEDITABLE, ListType.REMOVEONLY]) if list_type in [ListType.READONLY, ListType.REMOVEONLY]: padding = 0 else: padding = 6 self._set_child_packing(padding) self._list_type = list_type def clear(self): """Removes all the items in the list""" self.list.clear() # Callbacks def _on_list__selection_changed(self, list, selection): object_selected = selection is not None self.remove_button.set_sensitive(object_selected) self.edit_button.set_sensitive(object_selected) self.emit('selection-changed', selection) def _on_list__row_activated(self, list, item): if self._list_type not in [ListType.READONLY, ListType.ADDONLY, ListType.UNEDITABLE]: self._edit_item(item) def _on_add_button__clicked(self, button): self._add_item() def _on_remove_button__clicked(self, button): self._remove_item(self.list.get_selected()) def _on_edit_button__clicked(self, button): self._edit_item(self.list.get_selected())
class MethodTest(unittest.TestCase): def setUp(self): self.klist = ObjectList([Column('name', sorted=True)], [Settable(name='first')]) def testNonZero(self): self.assertEqual(self.klist.__nonzero__(), True) self.klist.remove(self.klist[0]) self.assertEqual(self.klist.__nonzero__(), True) if not self.klist: raise AssertionError def testIter(self): for item1 in self.klist: pass for item2 in iter(self.klist): self.assertEqual(item1, item2) def testGetItem(self): self.klist.append(Settable(name='second')) model = self.klist.get_model() item1 = model[0][0] item2 = model[1][0] self.assertEqual(self.klist[0], item1) self.assertEqual(self.klist[:1], [item1]) self.assertEqual(self.klist[-1:], [item2]) self.assertRaises(TypeError, self.klist.__getitem__, None) def testSetItem(self): self.klist[0] = Settable(name='second') self.assertRaises(NotImplementedError, self.klist.__setitem__, slice(0), None) self.assertRaises(TypeError, self.klist.__setitem__, None, None) def testIndex(self): self.assertRaises(NotImplementedError, self.klist.index, 0, start=0) self.assertRaises(NotImplementedError, self.klist.index, 0, stop=0) self.assertEqual(self.klist.index(self.klist[0]), 0) self.assertRaises(ValueError, self.klist.index, None) def testCount(self): item = self.klist[0] self.assertEqual(self.klist.count(item), 1) self.klist.append(item) self.assertEqual(self.klist.count(item), 2) self.klist.clear() self.assertEqual(self.klist.count(item), 0) def testPop(self): self.assertRaises(NotImplementedError, self.klist.pop, None) def testReverse(self): self.assertRaises(NotImplementedError, self.klist.reverse, 1, 2) def testSort(self): self.assertRaises(NotImplementedError, self.klist.sort, 1, 2) def testSelectPath(self): self.klist.get_treeview().get_selection().set_mode(gtk.SELECTION_NONE) self.assertRaises(TypeError, self.klist.select_paths, (0,)) self.klist.get_treeview().get_selection().set_mode(gtk.SELECTION_SINGLE) self.klist.select_paths((0,)) def testSelect(self): self.klist.get_treeview().get_selection().set_mode(gtk.SELECTION_NONE) self.assertRaises(TypeError, self.klist.select, None) self.klist.get_treeview().get_selection().set_mode(gtk.SELECTION_SINGLE) def testGetSelected(self): item = self.klist[0] self.klist.select(item) self.klist.get_treeview().get_selection().set_mode(gtk.SELECTION_SINGLE) self.assertEqual(self.klist.get_selected(), item) def testGetSelectedRows(self): self.klist.get_treeview().get_selection().set_mode(gtk.SELECTION_MULTIPLE) item = self.klist[0] self.klist.select(item) self.assertEqual(self.klist.get_selected_rows(), [item]) def testGetNextAndPrevious(self): self.klist.append(Settable(name='second')) self.klist.append(Settable(name='third')) item1, item2, item3 = self.klist self.assertEqual(self.klist.get_next(item1), item2) self.assertEqual(self.klist.get_next(item2), item3) self.assertEqual(self.klist.get_next(item3), item1) self.assertRaises(ValueError, self.klist.get_next, None) self.assertEqual(self.klist.get_previous(item1), item3) self.assertEqual(self.klist.get_previous(item2), item1) self.assertEqual(self.klist.get_previous(item3), item2) self.assertRaises(ValueError, self.klist.get_previous, None) def testInsert(self): self.klist = ObjectList([Column('name')]) self.assertEqual(list(self.klist), []) self.klist.insert(0, Settable(name='one')) self.assertEqual(self.klist[0].name, 'one') self.klist.insert(0, Settable(name='two')) self.assertEqual(self.klist[0].name, 'two') self.assertEqual(self.klist[1].name, 'one') self.klist.insert(1, Settable(name='three')) self.assertEqual(self.klist[0].name, 'two') self.assertEqual(self.klist[1].name, 'three') self.assertEqual(self.klist[2].name, 'one')
class Connections(GladeWidget): gladeFile = "connections.glade" gsignal("have-connection", bool) gsignal("connection-activated", object) gsignal("connections-cleared") def __init__(self): GladeWidget.__init__(self) columns = [ Column("host", title=_("Hostname"), searchable=True), Column( "timestamp", title=_("Last used"), sorted=True, order=gtk.SORT_DESCENDING, format_func=format_timestamp ), ] self._connections = ObjectList(columns, objects=getRecentConnections(), mode=gtk.SELECTION_SINGLE) self._connections.connect("row-activated", self._on_objectlist_row_activated) self._connections.connect("selection-changed", self._on_objectlist_selection_changed) self._connections.set_size_request(-1, 160) self.page.pack_start(self._connections) self.page.reorder_child(self._connections, 0) self._connections.get_treeview().set_search_equal_func(self._searchEqual) self._connections.show() self._updateButtons() def _updateButtons(self): canClear = hasRecentConnections() self.button_clear.set_sensitive(canClear) self.button_clear_all.set_sensitive(canClear) if not canClear: self.emit("connections-cleared") def _searchEqual(self, model, column, key, iter): connection = model.get(iter, column)[0] if key in connection.name: return False # True means doesn't match return True def _clear_all(self): for conn in self._connections: os.unlink(conn.filename) self._connections.clear() def _clear(self, conn): self._connections.remove(conn) os.unlink(conn.filename) # Public API def grab_focus(self): if len(self._connections): self._connections.select(self._connections[0]) self._connections.grab_focus() def get_selected(self): return self._connections.get_selected() def update(self, connection): os.utime(connection.filename, None) # Callbacks def on_button_clear_clicked(self, button): conn = self._connections.get_selected() if conn: self._clear(conn) self._updateButtons() def on_button_clear_all_clicked(self, button): self._clear_all() self._updateButtons() def _on_objectlist_row_activated(self, connections, connection): self.emit("connection-activated", connection) def _on_objectlist_selection_changed(self, connections, connection): self.emit("have-connection", bool(connection))
class BookmarkView(PidaView): icon_name = 'gtk-library' label_text = _('Bookmarks') def create_ui(self): self._vbox = gtk.VBox() self.create_toolbar() self.create_ui_list() self.add_main_widget(self._vbox) self._vbox.show_all() def create_tab_label(self, icon_name, text): if None in [icon_name, text]: return None label = gtk.Label(text) b_factory = gtk.HBox b = b_factory(spacing=2) icon = gtk.image_new_from_stock(icon_name, gtk.ICON_SIZE_MENU) b.pack_start(icon) b.pack_start(label) b.show_all() return b def create_ui_list(self): self._books = gtk.Notebook() self._books.set_border_width(6) self._list_dirs = ObjectList([Column('markup', data_type=str, use_markup=True)]) self._list_dirs.connect('row-activated', self._on_item_activated) self._list_dirs.connect('selection-changed', self._on_item_selected) self._list_dirs.set_headers_visible(False) self._list_dirs.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self._books.append_page(self._list_dirs, tab_label=self.create_tab_label('stock_folder', _('Dirs'))) self._list_files = ObjectList([Column('markup', data_type=str, use_markup=True)]) self._list_files.connect('row-activated', self._on_item_activated) self._list_files.connect('selection-changed', self._on_item_selected) self._list_files.set_headers_visible(False) self._list_files.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self._books.append_page(self._list_files, tab_label=self.create_tab_label('text-x-generic', _('Files'))) """ self._list_url = ObjectList([Column('markup', data_type=str, use_markup=True)]) self._list_url.set_headers_visible(False) self._books.add(self._list_url) """ self._vbox.add(self._books) self._books.show_all() def create_toolbar(self): self._uim = gtk.UIManager() self._uim.insert_action_group(self.svc.get_action_group(), 0) self._uim.add_ui_from_file(get_uidef_path('bookmark-toolbar.xml')) self._uim.ensure_update() self._toolbar = self._uim.get_toplevels('toolbar')[0] self._toolbar.set_style(gtk.TOOLBAR_ICONS) self._toolbar.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR) self._vbox.pack_start(self._toolbar, expand=False) self._toolbar.show_all() def add_item(self, item): if item.group == 'file': self._list_files.append(item) elif item.group == 'path': self._list_dirs.append(item) elif item.group == 'url': self._list_urls.append(item) def remove_item(self, item): if item.group == 'file': self._list_files.remove(item) elif item.group == 'path': self._list_dirs.remove(item) elif item.group == 'url': self._list_urls.remove(item) def clear_all(self): self._list_files.clear() self._list_dirs.clear() #self._list_urls.clear() def can_be_closed(self): self.svc.get_action('show_bookmark').set_active(False) def _on_item_selected(self, olist, item): self.svc.set_current(item) def _on_item_activated(self, olist, item): item.run(self.svc)
class ListContainer(Gtk.Box): """A ListContainer is an :class:`ObjectList` with buttons to be able to modify the content of the list. Depending on the list_mode, @see :class:`set_list_mode` you will have add, remove and edit buttons. Signals ======= - B{add-item} (returns item): - emitted when the add button is clicked, you're expected to return an object here - B{remove-item} (item, returns bool): - emitted when removing an item, you can block the removal from the list by returning False - B{edit-item} (item): - emitted when editing an item you can block the update afterwards by returning False :ivar add_button: add button :type add_button: :class:`Gtk.Button` :ivar remove_button: remove button :type remove_button: :class:`Gtk.Button` :ivar edit_button: edit button :type edit_button: :class:`Gtk.Button` """ __gtype_name__ = 'ListContainer' gsignal('add-item', retval=object) gsignal('remove-item', object, retval=bool) gsignal('edit-item', object, retval=bool) gsignal('selection-changed', object) def __init__(self, columns, orientation=Gtk.Orientation.VERTICAL): """ Create a new ListContainer object. :param columns: columns for the :class:`kiwi.ui.objectlist.ObjectList` :type columns: a list of :class:`kiwi.ui.objectlist.Columns` :param orientation: the position where the buttons will be placed: at the right (vertically) or at the bottom (horizontally) of the list. Defaults to the right of the list. :type: Gtk.Orientation.HORIZONTAL or Gtk.Orientation.VERTICAL """ self._list_type = None super(ListContainer, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) self._orientation = orientation self._create_ui(columns) self.set_list_type(ListType.NORMAL) # Private API def _create_ui(self, columns): self.list = ObjectList(columns) self.list.connect('selection-changed', self._on_list__selection_changed) self.list.connect('row-activated', self._on_list__row_activated) self.add_button = Gtk.Button(stock=Gtk.STOCK_ADD) self.add_button.connect('clicked', self._on_add_button__clicked) self.remove_button = Gtk.Button(stock=Gtk.STOCK_REMOVE) self.remove_button.set_sensitive(False) self.remove_button.connect('clicked', self._on_remove_button__clicked) self.edit_button = Gtk.Button(stock=Gtk.STOCK_EDIT) self.edit_button.set_sensitive(False) self.edit_button.connect('clicked', self._on_edit_button__clicked) self._vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) if self._orientation == Gtk.Orientation.VERTICAL: self.pack_start(self.list, True, True, 0) self.list.show() self._add_buttons_to_box(self._vbox) self._pack_vbox() elif self._orientation == Gtk.Orientation.HORIZONTAL: self._vbox.pack_start(self.list, True, True, 0) self.list.show() hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) self._add_buttons_to_box(hbox) self._vbox.pack_start(hbox, False, True, 0) hbox.show() self._pack_vbox() else: raise TypeError( "buttons_orientation must be Gtk.Orientation.VERTICAL " " or Gtk.Orientation.HORIZONTAL") def _add_buttons_to_box(self, box): box.pack_start(self.add_button, False, True, 0) box.pack_start(self.remove_button, False, True, 0) box.pack_start(self.edit_button, False, True, 0) def _pack_vbox(self): self.pack_start(self._vbox, False, True, 6) self._vbox.show() def _set_child_packing(self, padding): expand = self._orientation == Gtk.Orientation.HORIZONTAL self.set_child_packing(self._vbox, expand, True, padding, Gtk.PackType.START) def _add_item(self): retval = self.emit('add-item') if retval is None: return elif isinstance(retval, NotImplementedError): raise retval self.list.append(retval) self.list.refresh() def _remove_item(self, item): retval = self.emit('remove-item', item) if retval: self.list.remove(item) def _edit_item(self, item): retval = self.emit('edit-item', item) if retval: self.list.update(item) # Public API def add_item(self, item): """Appends an item to the list :param item: item to append """ self.list.append(item) def add_items(self, items): """Appends a list of items to the list :param items: items to add :type items: a sequence of items """ self.list.extend(items) def remove_item(self, item): """Removes an item from the list :param item: item to remove """ self.list.remove(item) def update_item(self, item): """Updates an item in the list. You should call this if you change the object :param item: item to update """ self.list.update(item) def default_remove(self, item): """Asks the user confirmation for removal of an item. :param item: a description of the item that will be removed :returns: True if the user confirm the removal, False otherwise """ response = yesno(_('Do you want to remove %s ?') % (GLib.markup_escape_text(str(item)), ), parent=None, default=Gtk.ResponseType.OK, buttons=((Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL), (Gtk.STOCK_REMOVE, Gtk.ResponseType.OK))) return response == Gtk.ResponseType.OK def set_list_type(self, list_type): """Sets the kind of list type. :param list_type: """ if not isinstance(list_type, ListType): raise TypeError("list_type must be a ListType enum") self.add_button.set_property( 'visible', list_type not in [ ListType.READONLY, ListType.REMOVEONLY, ListType.UNADDABLE ]) self.remove_button.set_property( 'visible', list_type not in [ListType.READONLY, ListType.ADDONLY, ListType.UNREMOVABLE]) self.edit_button.set_property( 'visible', list_type not in [ ListType.READONLY, ListType.ADDONLY, ListType.UNEDITABLE, ListType.REMOVEONLY ]) if list_type in [ListType.READONLY, ListType.REMOVEONLY]: padding = 0 else: padding = 6 self._set_child_packing(padding) self._list_type = list_type def clear(self): """Removes all the items in the list""" self.list.clear() # Callbacks def _on_list__selection_changed(self, list, selection): object_selected = selection is not None self.remove_button.set_sensitive(object_selected) self.edit_button.set_sensitive(object_selected) self.emit('selection-changed', selection) def _on_list__row_activated(self, list, item): if self._list_type not in [ ListType.READONLY, ListType.ADDONLY, ListType.UNEDITABLE ]: self._edit_item(item) def _on_add_button__clicked(self, button): self._add_item() def _on_remove_button__clicked(self, button): self._remove_item(self.list.get_selected()) def _on_edit_button__clicked(self, button): self._edit_item(self.list.get_selected())