openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #29220
[Merge] lp:~knightrider0xd/openlp/auto-scroll-choice into lp:openlp
Ian Knight has proposed merging lp:~knightrider0xd/openlp/auto-scroll-choice into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
Related bugs:
Bug #1550858 in OpenLP: "Choose behaviour for auto-scroll of slides in slide-controller"
https://bugs.launchpad.net/openlp/+bug/1550858
For more details, see:
https://code.launchpad.net/~knightrider0xd/openlp/auto-scroll-choice/+merge/292064
Allows users to change the automatic scrolling behaviour for when a new slide is selected.
Currently on selecting a new slide, the next slide will be scrolled into view.
The changes provide a combo-box in the advanced settings that allow users to select additional options (see branch description for details).
Additional bounds checking and unit tests have been added to support this.
--
Your team OpenLP Core is requested to review the proposed merge of lp:~knightrider0xd/openlp/auto-scroll-choice into lp:openlp.
=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py 2016-03-20 15:00:15 +0000
+++ openlp/core/common/settings.py 2016-04-16 07:20:31 +0000
@@ -107,6 +107,7 @@
__default_settings__ = {
'advanced/add page break': False,
'advanced/alternate rows': not is_win(),
+ 'advanced/autoscrolling': {'dist': 1, 'pos': 0},
'advanced/current media plugin': -1,
'advanced/data path': '',
'advanced/default color': '#ffffff',
@@ -121,7 +122,6 @@
'advanced/double click live': False,
'advanced/enable exit confirmation': True,
'advanced/expand service item': False,
- 'advanced/slide max height': 0,
'advanced/hide mouse': True,
'advanced/is portable': False,
'advanced/max recent files': 20,
@@ -131,6 +131,7 @@
'advanced/recent file count': 4,
'advanced/save current plugin': False,
'advanced/slide limits': SlideLimits.End,
+ 'advanced/slide max height': 0,
'advanced/single click preview': False,
'advanced/single click service preview': False,
'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
=== modified file 'openlp/core/ui/advancedtab.py'
--- openlp/core/ui/advancedtab.py 2016-04-05 17:30:20 +0000
+++ openlp/core/ui/advancedtab.py 2016-04-16 07:20:31 +0000
@@ -49,6 +49,10 @@
self.default_color = '#ffffff'
self.data_exists = False
self.icon_path = ':/system/system_settings.png'
+ self.autoscroll_map = [None, {'dist': -1, 'pos': 0}, {'dist': -1, 'pos': 1}, {'dist': -1, 'pos': 2},
+ {'dist': 0, 'pos': 0}, {'dist': 0, 'pos': 1}, {'dist': 0, 'pos': 2},
+ {'dist': 0, 'pos': 3}, {'dist': 1, 'pos': 0}, {'dist': 1, 'pos': 1},
+ {'dist': 1, 'pos': 2}, {'dist': 1, 'pos': 3}]
advanced_translated = translate('OpenLP.AdvancedTab', 'Advanced')
super(AdvancedTab, self).__init__(parent, 'Advanced', advanced_translated)
@@ -90,6 +94,13 @@
self.slide_max_height_spin_box.setRange(0, 1000)
self.slide_max_height_spin_box.setSingleStep(20)
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_spin_box)
+ self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box)
+ self.autoscroll_label.setObjectName('autoscroll_label')
+ self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box)
+ self.autoscroll_combo_box.addItems(['', '', '', '', '', '', '', '', '', '', '', ''])
+ self.autoscroll_combo_box.setObjectName('autoscroll_combo_box')
+ self.ui_layout.addRow(self.autoscroll_label)
+ self.ui_layout.addRow(self.autoscroll_combo_box)
self.search_as_type_check_box = QtWidgets.QCheckBox(self.ui_group_box)
self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
self.ui_layout.addRow(self.search_as_type_check_box)
@@ -287,6 +298,31 @@
self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab',
'Max height for non-text slides\nin slide controller:'))
self.slide_max_height_spin_box.setSpecialValueText(translate('OpenLP.AdvancedTab', 'Disabled'))
+ self.autoscroll_label.setText(translate('OpenLP.AdvancedTab',
+ 'When changing slides:'))
+ self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll'))
+ self.autoscroll_combo_box.setItemText(1, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the previous slide into view'))
+ self.autoscroll_combo_box.setItemText(2, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the previous slide to top'))
+ self.autoscroll_combo_box.setItemText(3, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the previous slide to middle'))
+ self.autoscroll_combo_box.setItemText(4, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the current slide into view'))
+ self.autoscroll_combo_box.setItemText(5, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the current slide to top'))
+ self.autoscroll_combo_box.setItemText(6, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the current slide to middle'))
+ self.autoscroll_combo_box.setItemText(7, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the current slide to bottom'))
+ self.autoscroll_combo_box.setItemText(8, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the next slide into view'))
+ self.autoscroll_combo_box.setItemText(9, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the next slide to top'))
+ self.autoscroll_combo_box.setItemText(10, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the next slide to middle'))
+ self.autoscroll_combo_box.setItemText(11, translate('OpenLP.AdvancedTab',
+ 'Auto-scroll the next slide to bottom'))
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
'Enable application exit confirmation'))
self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
@@ -357,6 +393,10 @@
self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview'))
self.expand_service_item_check_box.setChecked(settings.value('expand service item'))
self.slide_max_height_spin_box.setValue(settings.value('slide max height'))
+ autoscroll_value = settings.value('autoscrolling')
+ for i in range(0, len(self.autoscroll_map)):
+ if self.autoscroll_map[i] == autoscroll_value:
+ self.autoscroll_combo_box.setCurrentIndex(i)
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
self.service_name_day.setCurrentIndex(settings.value('default service day'))
@@ -440,6 +480,7 @@
settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked())
settings.setValue('expand service item', self.expand_service_item_check_box.isChecked())
settings.setValue('slide max height', self.slide_max_height_spin_box.value())
+ settings.setValue('autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()])
settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked())
settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked())
settings.setValue('alternate rows', self.alternate_rows_check_box.isChecked())
=== modified file 'openlp/core/ui/listpreviewwidget.py'
--- openlp/core/ui/listpreviewwidget.py 2016-03-05 16:41:32 +0000
+++ openlp/core/ui/listpreviewwidget.py 2016-04-16 07:20:31 +0000
@@ -194,11 +194,21 @@
"""
Switches to the given row.
"""
- if slide >= self.slide_count():
- slide = self.slide_count() - 1
- # Scroll to next item if possible.
- if slide + 1 < self.slide_count():
- self.scrollToItem(self.item(slide + 1, 0))
+ # Retrieve setting
+ autoscrolling = Settings().value('advanced/autoscrolling')
+ # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos'
+ # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next)
+ # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom)
+ if (not isinstance(autoscrolling, dict)) or ('dist' not in autoscrolling) or ('pos' not in autoscrolling):
+ return
+ # prevent scrolling past list bounds
+ scroll_to_slide = slide + autoscrolling['dist']
+ if scroll_to_slide < 0:
+ scroll_to_slide = 0
+ if scroll_to_slide >= self.slide_count():
+ scroll_to_slide = self.slide_count() - 1
+ # Scroll to item if possible.
+ self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos'])
self.selectRow(slide)
def current_slide_number(self):
=== modified file 'tests/functional/openlp_core_ui/test_listpreviewwidget.py'
--- tests/functional/openlp_core_ui/test_listpreviewwidget.py 2016-03-23 14:14:37 +0000
+++ tests/functional/openlp_core_ui/test_listpreviewwidget.py 2016-04-16 07:20:31 +0000
@@ -273,3 +273,95 @@
# THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should be called
mocked_cellWidget_child.setMaximumWidth.assert_called_once_with(150)
+
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count')
+ def autoscroll_test_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
+ """
+ Test if 'advanced/autoscrolling' setting None or invalid, that no autoscrolling occurs on change_slide().
+ """
+ # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
+ # Mock Settings().value('advanced/autoscrolling')
+ self.mocked_Settings_obj.value.return_value = None
+ # Mocked returns
+ mocked_slide_count.return_value = 1
+ mocked_item.return_value = None
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # WHEN: change_slide() is called
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = 1
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'test': 1}
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'test': 1}
+ list_preview_widget.change_slide(0)
+
+ # THEN: no further functions should be called
+ self.assertEquals(mocked_slide_count.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_item.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_scrollToItem.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_selectRow.call_count, 0, 'Should not be called')
+
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count')
+ def autoscroll_test_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
+ """
+ Test if 'advanced/autoscrolling' setting asks to scroll beyond list bounds, that it does not beyond.
+ """
+ # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
+ # Mock Settings().value('advanced/autoscrolling')
+ self.mocked_Settings_obj.value.return_value = {'dist': -1, 'pos': 1}
+ # Mocked returns
+ mocked_slide_count.return_value = 1
+ mocked_item.return_value = None
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # WHEN: change_slide() is called
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 1}
+ list_preview_widget.change_slide(0)
+
+ # THEN: no further functions should be called
+ self.assertEquals(mocked_slide_count.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_scrollToItem.call_count, 2, 'Should be called')
+ self.assertEquals(mocked_selectRow.call_count, 2, 'Should be called')
+ calls = [call(0, 0), call(0, 0)]
+ mocked_item.assert_has_calls(calls)
+
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item')
+ @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count')
+ def autoscroll_test_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
+ """
+ Test if 'advanced/autoscrolling' setting valid, autoscrolling called as expected.
+ """
+ # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
+ # Mock Settings().value('advanced/autoscrolling')
+ self.mocked_Settings_obj.value.return_value = {'dist': -1, 'pos': 1}
+ # Mocked returns
+ mocked_slide_count.return_value = 3
+ mocked_item.return_value = None
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # WHEN: change_slide() is called
+ list_preview_widget.change_slide(1)
+ self.mocked_Settings_obj.value.return_value = {'dist': 0, 'pos': 1}
+ list_preview_widget.change_slide(1)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 1}
+ list_preview_widget.change_slide(1)
+
+ # THEN: no further functions should be called
+ self.assertEquals(mocked_slide_count.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_scrollToItem.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_selectRow.call_count, 3, 'Should be called')
+ calls = [call(0, 0), call(1, 0), call(2, 0)]
+ mocked_item.assert_has_calls(calls)
Follow ups