def test_list_adapter_selection_mode_multiple_auto_selection(self): list_adapter = ListAdapter( data=fruit_data_items, args_converter=self.args_converter, selection_mode='multiple', propagate_selection_to_data=True, allow_empty_selection=False, cls=ListItemButton) list_view = ListView(adapter=list_adapter) # The reason why len(selection) == 1 here is because ListView, # at the end of its __init__(), calls check_for_empty_selection() # and triggers the initial selection, because allow_empty_selection is # False. self.assertEqual(len(list_adapter.selection), 1) apple = list_adapter.selection[0] self.assertEqual(apple.text, 'Apple') # Add Avocado to the selection, doing necessary steps on data first. self.assertEqual(fruit_data_items[1].name, 'Avocado') fruit_data_items[1].is_selected = True avocado = list_view.adapter.get_view(1) # does selection self.assertEqual(avocado.text, 'Avocado') self.assertEqual(len(list_adapter.selection), 2) # Re-selection of the same item should decrease the len by 1. list_adapter.handle_selection(avocado) self.assertEqual(len(list_adapter.selection), 1) # And now only apple should be in selection. self.assertEqual(list_adapter.selection, [apple]) # Selection of several different items should increment len, # because we have selection_mode as multiple. # # avocado has been unselected. Select it again. list_adapter.handle_selection(avocado) self.assertEqual(len(list_adapter.selection), 2) self.assertEqual(list_adapter.selection, [apple, avocado]) # And select some different ones. self.assertEqual(fruit_data_items[2].name, 'Banana') fruit_data_items[2].is_selected = True banana = list_view.adapter.get_view(2) # does selection self.assertEqual(list_adapter.selection, [apple, avocado, banana]) self.assertEqual(len(list_adapter.selection), 3)
def test_list_adapter_selection_mode_multiple_auto_selection(self): list_adapter = ListAdapter(data=fruit_data_items, args_converter=self.args_converter, selection_mode='multiple', propagate_selection_to_data=True, allow_empty_selection=False, cls=ListItemButton) list_view = ListView(adapter=list_adapter) # The reason why len(selection) == 1 here is because ListView, # at the end of its __init__(), calls check_for_empty_selection() # and triggers the initial selection, because allow_empty_selection is # False. self.assertEqual(len(list_adapter.selection), 1) apple = list_adapter.selection[0] self.assertEqual(apple.text, 'Apple') # Add Avocado to the selection, doing necessary steps on data first. self.assertEqual(fruit_data_items[1].name, 'Avocado') fruit_data_items[1].is_selected = True avocado = list_view.adapter.get_view(1) # does selection self.assertEqual(avocado.text, 'Avocado') self.assertEqual(len(list_adapter.selection), 2) # Re-selection of the same item should decrease the len by 1. list_adapter.handle_selection(avocado) self.assertEqual(len(list_adapter.selection), 1) # And now only apple should be in selection. self.assertEqual(list_adapter.selection, [apple]) # Selection of several different items should increment len, # because we have selection_mode as multiple. # # avocado has been unselected. Select it again. list_adapter.handle_selection(avocado) self.assertEqual(len(list_adapter.selection), 2) self.assertEqual(list_adapter.selection, [apple, avocado]) # And select some different ones. self.assertEqual(fruit_data_items[2].name, 'Banana') fruit_data_items[2].is_selected = True banana = list_view.adapter.get_view(2) # does selection self.assertEqual(list_adapter.selection, [apple, avocado, banana]) self.assertEqual(len(list_adapter.selection), 3)
def test_list_adapter_selection_handle_selection(self): list_adapter = ListAdapter(data=fruit_data_items, args_converter=self.args_converter, selection_mode='single', propagate_selection_to_data=True, allow_empty_selection=False, cls=ListItemButton) selection_observer = FruitSelectionObserver() list_adapter.bind( on_selection_change=selection_observer.on_selection_change) list_view = ListView(adapter=list_adapter) self.assertEqual(selection_observer.call_count, 0) # From the check for initial selection, we should have apple selected. self.assertEqual(list_adapter.selection[0].text, 'Apple') self.assertEqual(len(list_adapter.selection), 1) # Go through the tests routine to trigger selection of banana. # (See notes above about triggering selection in tests.) self.assertEqual(fruit_data_items[2].name, 'Banana') fruit_data_items[2].is_selected = True banana = list_view.adapter.get_view(2) # does selection self.assertTrue(banana.is_selected) # Now unselect it with handle_selection(). list_adapter.handle_selection(banana) self.assertFalse(banana.is_selected) # But, since we have allow_empty_selection=False, Apple will be # reselected. self.assertEqual(selection_observer.fruit_name, 'Apple') # Call count: # # Apple got selected initally (0), then unselected when Banana was # selected (1). Then banana was unselected, causing reselection of # Apple (3). len should be 1. self.assertEqual(selection_observer.call_count, 3) self.assertEqual(len(list_adapter.selection), 1)
class NewProjectDialog(BoxLayout): listview = ObjectProperty(None) ''':class:`~kivy.uix.listview.ListView` used for showing file paths. :data:`listview` is a :class:`~kivy.properties.ObjectProperty` ''' select_button = ObjectProperty(None) ''':class:`~kivy.uix.button.Button` used to select the list item. :data:`select_button` is a :class:`~kivy.properties.ObjectProperty` ''' cancel_button = ObjectProperty(None) ''':class:`~kivy.uix.button.Button` to cancel the dialog. :data:`cancel_button` is a :class:`~kivy.properties.ObjectProperty` ''' adapter = ObjectProperty(None) ''':class:`~kivy.uix.listview.ListAdapter` used for selecting files. :data:`adapter` is a :class:`~kivy.properties.ObjectProperty` ''' image = ObjectProperty(None) '''Type of :class:`~kivy.uix.image.Image` to display image of selected new template. :data:`image` is a :class:`~kivy.properties.ObjectProperty` ''' list_parent = ObjectProperty(None) '''Parent of listview. :data:`list_parent` is a :class:`~kivy.properties.ObjectProperty` ''' prev_selection = NumericProperty(0) '''to memorize the previous selection. :attr:`prev_selection` is a :class: `~kivy.properties.NumericProperty`, defaults to (0). ''' __events__ = ('on_select', 'on_cancel') def __init__(self, **kwargs): super(NewProjectDialog, self).__init__(**kwargs) item_strings = list(NEW_PROJECTS.keys()) item_strings.sort() self.adapter = ListAdapter(cls=Factory.DesignerListItemButton, data=item_strings, selection_mode='single', allow_empty_selection=False) self.adapter.check_for_empty_selection = self.check_for_empty_selection self.adapter.bind(on_selection_change=self.on_adapter_selection_change) self.listview = ListView(adapter=self.adapter) self.listview.size_hint = (0.5, 1) self.listview.pos_hint = {'top': 1} self.list_parent.add_widget(self.listview, 1) self.on_adapter_selection_change(self.adapter) def on_parent(self, *args): if self.parent: Window.bind(on_key_down=self._on_keyboard_down) else: Window.unbind(on_key_down=self._on_keyboard_down) def _on_keyboard_down(self, keyboard, key, codepoint, text, modifier, *args): '''To detect which key is pressed ''' if modifier: return False key_str = Keyboard.keycode_to_string(Window._system_keyboard, key) if key_str == 'up': v = self.adapter.get_view(self.prev_selection - 1) if v is not None: self.adapter.handle_selection(v) return True if key_str == 'down': v = self.adapter.get_view(self.prev_selection + 1) if v is not None: self.adapter.handle_selection(v) return True if key_str == 'enter': self.dispatch('on_select') return True def check_for_empty_selection(self, *args): if not self.adapter.allow_empty_selection: if len(self.adapter.selection) == 0: # Select the first item if we have it. v = self.adapter.get_view(self.prev_selection) if v is not None: self.adapter.handle_selection(v) def on_adapter_selection_change(self, adapter): '''Event handler for 'on_selection_change' event of adapter. ''' name = adapter.selection[0].text.lower() + '.png' name = name.replace(' and ', '_') image_source = join(NEW_TEMPLATE_IMAGE_PATH, name) _dir = get_kd_dir() image_source = join(_dir, image_source) parent = self.image.parent parent.remove_widget(self.image) self.image = Image(source=image_source) parent.add_widget(self.image) self.prev_selection = adapter.data.index(adapter.selection[0].text) def on_touch_down(self, touch): '''Used to determine where touch is down and to detect double tap. ''' if touch.is_double_tap: self.dispatch('on_select') return super(NewProjectDialog, self).on_touch_down(touch) def on_select(self, *args): '''Default Event Handler for 'on_select' event ''' pass def on_cancel(self, *args): '''Default Event Handler for 'on_cancel' event ''' pass def on_select_button(self, *args): '''Event Handler for 'on_release' of select button. ''' self.select_button.bind(on_press=partial(self.dispatch, 'on_select')) def on_cancel_button(self, *args): '''Event Handler for 'on_release' of cancel button. ''' self.cancel_button.bind(on_press=partial(self.dispatch, 'on_cancel'))
class NewProjectDialog(BoxLayout): listview = ObjectProperty(None) ''':class:`~kivy.uix.listview.ListView` used for showing file paths. :data:`listview` is a :class:`~kivy.properties.ObjectProperty` ''' select_button = ObjectProperty(None) ''':class:`~kivy.uix.button.Button` used to select the list item. :data:`select_button` is a :class:`~kivy.properties.ObjectProperty` ''' cancel_button = ObjectProperty(None) ''':class:`~kivy.uix.button.Button` to cancel the dialog. :data:`cancel_button` is a :class:`~kivy.properties.ObjectProperty` ''' adapter = ObjectProperty(None) ''':class:`~kivy.uix.listview.ListAdapter` used for selecting files. :data:`adapter` is a :class:`~kivy.properties.ObjectProperty` ''' image = ObjectProperty(None) '''Type of :class:`~kivy.uix.image.Image` to display image of selected new template. :data:`image` is a :class:`~kivy.properties.ObjectProperty` ''' list_parent = ObjectProperty(None) '''Parent of listview. :data:`list_parent` is a :class:`~kivy.properties.ObjectProperty` ''' prev_selection = NumericProperty(0) '''to memorize the previous selection. :attr:`prev_selection` is a :class: `~kivy.properties.NumericProperty`, defaults to (0). ''' __events__ = ('on_select', 'on_cancel') def __init__(self, **kwargs): super(NewProjectDialog, self).__init__(**kwargs) item_strings = list(NEW_PROJECTS.keys()) item_strings.sort() self.adapter = ListAdapter(cls=Factory.DesignerListItemButton, data=item_strings, selection_mode='single', allow_empty_selection=False) self.adapter.check_for_empty_selection = self.check_for_empty_selection self.adapter.bind(on_selection_change=self.on_adapter_selection_change) self.listview = ListView(adapter=self.adapter) self.listview.size_hint = (0.5, 1) self.listview.pos_hint = {'top': 1} self.list_parent.add_widget(self.listview, 1) self.on_adapter_selection_change(self.adapter) def on_parent(self, *args): if self.parent: Window.bind(on_key_down=self._on_keyboard_down) else: Window.unbind(on_key_down=self._on_keyboard_down) def _on_keyboard_down(self, keyboard, key, codepoint, text, modifier, *args): '''To detect which key is pressed ''' if modifier: return False key_str = Keyboard.keycode_to_string(Window._system_keyboard, key) if key_str == 'up': v = self.adapter.get_view(self.prev_selection - 1) if v is not None: self.adapter.handle_selection(v) return True if key_str == 'down': v = self.adapter.get_view(self.prev_selection + 1) if v is not None: self.adapter.handle_selection(v) return True if key_str == 'enter': self.dispatch('on_select') return True def check_for_empty_selection(self, *args): if not self.adapter.allow_empty_selection: if len(self.adapter.selection) == 0: # Select the first item if we have it. v = self.adapter.get_view(self.prev_selection) if v is not None: self.adapter.handle_selection(v) def on_adapter_selection_change(self, adapter): '''Event handler for 'on_selection_change' event of adapter. ''' name = adapter.selection[0].text.lower() + '.png' name = name.replace(' and ', '_') image_source = join(constants.NEW_TEMPLATE_IMAGE_PATH, name) image_source = join(get_kd_data_dir(), image_source) parent = self.image.parent parent.remove_widget(self.image) self.image = Image(source=image_source) parent.add_widget(self.image) self.prev_selection = adapter.data.index(adapter.selection[0].text) def on_touch_down(self, touch): '''Used to determine where touch is down and to detect double tap. ''' if touch.is_double_tap: self.dispatch('on_select') return super(NewProjectDialog, self).on_touch_down(touch) def on_select(self, *args): '''Default Event Handler for 'on_select' event ''' pass def on_cancel(self, *args): '''Default Event Handler for 'on_cancel' event ''' pass def on_select_button(self, *args): '''Event Handler for 'on_release' of select button. ''' self.select_button.bind(on_press=partial(self.dispatch, 'on_select')) def on_cancel_button(self, *args): '''Event Handler for 'on_release' of cancel button. ''' self.cancel_button.bind(on_press=partial(self.dispatch, 'on_cancel'))