Merge lp:~knightrider0xd/openlp/preview-shows-live-fix-1080596 into lp:openlp

Proposed by Ian Knight
Status: Merged
Merged at revision: 2661
Proposed branch: lp:~knightrider0xd/openlp/preview-shows-live-fix-1080596
Merge into: lp:openlp
Diff against target: 687 lines (+472/-19)
9 files modified
openlp/core/lib/__init__.py (+26/-2)
openlp/core/lib/serviceitem.py (+2/-0)
openlp/core/ui/lib/listpreviewwidget.py (+8/-6)
openlp/core/ui/slidecontroller.py (+15/-3)
openlp/plugins/presentations/lib/presentationcontroller.py (+2/-2)
tests/functional/openlp_core_lib/test_lib.py (+190/-2)
tests/functional/openlp_core_lib/test_serviceitem.py (+5/-2)
tests/functional/openlp_core_ui/test_slidecontroller.py (+170/-1)
tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py (+54/-1)
To merge this branch: bzr merge lp:~knightrider0xd/openlp/preview-shows-live-fix-1080596
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Raoul Snyman Approve
Review via email: mp+294803@code.launchpad.net

This proposal supersedes a proposal from 2016-05-06.

Description of the change

Fixes bug 1080596 where presentations in the preview pane display live view rather than preview of selected slide.
In addition, fixes the aspect ratio & quality of thumbnails by saving them in the correct aspect ratio at a higher resolution, and loading them through the image manager.

New test cases implemented, or existing cases modified to test coverage complete for changes.

lp:~knightrider0xd/openlp/preview-shows-live-fix-1080596 (revision 2652)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1554/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1465/

Failing interface & coverage tests due to issue with unrelated crosswalk import module.

To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Just one clarification?

review: Needs Information
Revision history for this message
Raoul Snyman (raoul-snyman) wrote :

Looks OK to me.

review: Approve
Revision history for this message
Tim Bentley (trb143) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2016-04-23 19:28:52 +0000
+++ openlp/core/lib/__init__.py 2016-05-16 12:42:11 +0000
@@ -55,9 +55,13 @@
5555
56 ``Theme``56 ``Theme``
57 This says, that the image is used by a theme.57 This says, that the image is used by a theme.
58
59 ``CommandPlugins``
60 This states that an image is being used by a command plugin.
58 """61 """
59 ImagePlugin = 162 ImagePlugin = 1
60 Theme = 263 Theme = 2
64 CommandPlugins = 3
6165
6266
63class MediaType(object):67class MediaType(object):
@@ -174,10 +178,30 @@
174 ext = os.path.splitext(thumb_path)[1].lower()178 ext = os.path.splitext(thumb_path)[1].lower()
175 reader = QtGui.QImageReader(image_path)179 reader = QtGui.QImageReader(image_path)
176 if size is None:180 if size is None:
177 ratio = reader.size().width() / reader.size().height()181 # No size given; use default height of 88
182 if reader.size().isEmpty():
183 ratio = 1
184 else:
185 ratio = reader.size().width() / reader.size().height()
178 reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))186 reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))
179 else:187 elif size.isValid():
188 # Complete size given
180 reader.setScaledSize(size)189 reader.setScaledSize(size)
190 else:
191 # Invalid size given
192 if reader.size().isEmpty():
193 ratio = 1
194 else:
195 ratio = reader.size().width() / reader.size().height()
196 if size.width() >= 0:
197 # Valid width; scale height
198 reader.setScaledSize(QtCore.QSize(size.width(), int(size.width() / ratio)))
199 elif size.height() >= 0:
200 # Valid height; scale width
201 reader.setScaledSize(QtCore.QSize(int(ratio * size.height()), size.height()))
202 else:
203 # Invalid; use default height of 88
204 reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))
181 thumb = reader.read()205 thumb = reader.read()
182 thumb.save(thumb_path, ext[1:])206 thumb.save(thumb_path, ext[1:])
183 if not return_icon:207 if not return_icon:
184208
=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py 2016-02-14 17:53:16 +0000
+++ openlp/core/lib/serviceitem.py 2016-05-16 12:42:11 +0000
@@ -334,6 +334,8 @@
334 file_location_hash, ntpath.basename(image))334 file_location_hash, ntpath.basename(image))
335 self._raw_frames.append({'title': file_name, 'image': image, 'path': path,335 self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
336 'display_title': display_title, 'notes': notes})336 'display_title': display_title, 'notes': notes})
337 if self.is_capable(ItemCapabilities.HasThumbnails):
338 self.image_manager.add_image(image, ImageSource.CommandPlugins, '#000000')
337 self._new_item()339 self._new_item()
338340
339 def get_service_repr(self, lite_save):341 def get_service_repr(self, lite_save):
340342
=== modified file 'openlp/core/ui/lib/listpreviewwidget.py'
--- openlp/core/ui/lib/listpreviewwidget.py 2016-04-22 18:32:59 +0000
+++ openlp/core/ui/lib/listpreviewwidget.py 2016-05-16 12:42:11 +0000
@@ -27,7 +27,7 @@
27from PyQt5 import QtCore, QtGui, QtWidgets27from PyQt5 import QtCore, QtGui, QtWidgets
2828
29from openlp.core.common import RegistryProperties, Settings29from openlp.core.common import RegistryProperties, Settings
30from openlp.core.lib import ImageSource, ServiceItem30from openlp.core.lib import ImageSource, ItemCapabilities, ServiceItem
3131
3232
33class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):33class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
@@ -152,14 +152,16 @@
152 else:152 else:
153 label.setScaledContents(True)153 label.setScaledContents(True)
154 if self.service_item.is_command():154 if self.service_item.is_command():
155 pixmap = QtGui.QPixmap(frame['image'])155 if self.service_item.is_capable(ItemCapabilities.HasThumbnails):
156 pixmap.setDevicePixelRatio(label.devicePixelRatio())156 image = self.image_manager.get_image(frame['image'], ImageSource.CommandPlugins)
157 label.setPixmap(pixmap)157 pixmap = QtGui.QPixmap.fromImage(image)
158 else:
159 pixmap = QtGui.QPixmap(frame['image'])
158 else:160 else:
159 image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin)161 image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin)
160 pixmap = QtGui.QPixmap.fromImage(image)162 pixmap = QtGui.QPixmap.fromImage(image)
161 pixmap.setDevicePixelRatio(label.devicePixelRatio())163 pixmap.setDevicePixelRatio(label.devicePixelRatio())
162 label.setPixmap(pixmap)164 label.setPixmap(pixmap)
163 slide_height = width // self.screen_ratio165 slide_height = width // self.screen_ratio
164 # Setup and validate row height cap if in use.166 # Setup and validate row height cap if in use.
165 max_img_row_height = Settings().value('advanced/slide max height')167 max_img_row_height = Settings().value('advanced/slide max height')
166168
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2016-04-22 18:32:45 +0000
+++ openlp/core/ui/slidecontroller.py 2016-05-16 12:42:11 +0000
@@ -1135,9 +1135,21 @@
1135 """1135 """
1136 self.log_debug('update_preview %s ' % self.screens.current['primary'])1136 self.log_debug('update_preview %s ' % self.screens.current['primary'])
1137 if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):1137 if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
1138 # Grab now, but try again in a couple of seconds if slide change is slow1138 if self.is_live:
1139 QtCore.QTimer.singleShot(500, self.grab_maindisplay)1139 # If live, grab screen-cap of main display now
1140 QtCore.QTimer.singleShot(2500, self.grab_maindisplay)1140 QtCore.QTimer.singleShot(500, self.grab_maindisplay)
1141 # but take another in a couple of seconds in case slide change is slow
1142 QtCore.QTimer.singleShot(2500, self.grab_maindisplay)
1143 else:
1144 # If not live, use the slide's thumbnail/icon instead
1145 image_path = self.service_item.get_rendered_frame(self.selected_row)
1146 if self.service_item.is_capable(ItemCapabilities.HasThumbnails):
1147 image = self.image_manager.get_image(image_path, ImageSource.CommandPlugins)
1148 self.slide_image = QtGui.QPixmap.fromImage(image)
1149 else:
1150 self.slide_image = QtGui.QPixmap(image_path)
1151 self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio())
1152 self.slide_preview.setPixmap(self.slide_image)
1141 else:1153 else:
1142 self.slide_image = self.display.preview()1154 self.slide_image = self.display.preview()
1143 self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio())1155 self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio())
11441156
=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
--- openlp/plugins/presentations/lib/presentationcontroller.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/presentations/lib/presentationcontroller.py 2016-05-16 12:42:11 +0000
@@ -242,13 +242,13 @@
242242
243 def convert_thumbnail(self, file, idx):243 def convert_thumbnail(self, file, idx):
244 """244 """
245 Convert the slide image the application made to a standard 320x240 .png image.245 Convert the slide image the application made to a scaled 360px height .png image.
246 """246 """
247 if self.check_thumbnails():247 if self.check_thumbnails():
248 return248 return
249 if os.path.isfile(file):249 if os.path.isfile(file):
250 thumb_path = self.get_thumbnail_path(idx, False)250 thumb_path = self.get_thumbnail_path(idx, False)
251 create_thumb(file, thumb_path, False, QtCore.QSize(320, 240))251 create_thumb(file, thumb_path, False, QtCore.QSize(-1, 360))
252252
253 def get_thumbnail_path(self, slide_no, check_exists):253 def get_thumbnail_path(self, slide_no, check_exists):
254 """254 """
255255
=== modified file 'tests/functional/openlp_core_lib/test_lib.py'
--- tests/functional/openlp_core_lib/test_lib.py 2015-12-31 22:46:06 +0000
+++ tests/functional/openlp_core_lib/test_lib.py 2016-05-16 12:42:11 +0000
@@ -250,7 +250,7 @@
250250
251 def create_thumb_with_size_test(self):251 def create_thumb_with_size_test(self):
252 """252 """
253 Test the create_thumb() function253 Test the create_thumb() function with a given size.
254 """254 """
255 # GIVEN: An image to create a thumb of.255 # GIVEN: An image to create a thumb of.
256 image_path = os.path.join(TEST_PATH, 'church.jpg')256 image_path = os.path.join(TEST_PATH, 'church.jpg')
@@ -270,7 +270,7 @@
270 # WHEN: Create the thumb.270 # WHEN: Create the thumb.
271 icon = create_thumb(image_path, thumb_path, size=thumb_size)271 icon = create_thumb(image_path, thumb_path, size=thumb_size)
272272
273 # THEN: Check if the thumb was created.273 # THEN: Check if the thumb was created and scaled to the given size.
274 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')274 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
275 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')275 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
276 self.assertFalse(icon.isNull(), 'The icon should not be null')276 self.assertFalse(icon.isNull(), 'The icon should not be null')
@@ -282,6 +282,194 @@
282 except:282 except:
283 pass283 pass
284284
285 def create_thumb_no_size_test(self):
286 """
287 Test the create_thumb() function with no size specified.
288 """
289 # GIVEN: An image to create a thumb of.
290 image_path = os.path.join(TEST_PATH, 'church.jpg')
291 thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
292 expected_size = QtCore.QSize(63, 88)
293
294 # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
295 # last test.
296 try:
297 os.remove(thumb_path)
298 except:
299 pass
300
301 # Only continue when the thumb does not exist.
302 self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
303
304 # WHEN: Create the thumb.
305 icon = create_thumb(image_path, thumb_path)
306
307 # THEN: Check if the thumb was created, retaining its aspect ratio.
308 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
309 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
310 self.assertFalse(icon.isNull(), 'The icon should not be null')
311 self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
312
313 # Remove the thumb so that the test actually tests if the thumb will be created.
314 try:
315 os.remove(thumb_path)
316 except:
317 pass
318
319 def create_thumb_invalid_size_test(self):
320 """
321 Test the create_thumb() function with invalid size specified.
322 """
323 # GIVEN: An image to create a thumb of.
324 image_path = os.path.join(TEST_PATH, 'church.jpg')
325 thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
326 thumb_size = QtCore.QSize(-1, -1)
327 expected_size = QtCore.QSize(63, 88)
328
329 # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
330 # last test.
331 try:
332 os.remove(thumb_path)
333 except:
334 pass
335
336 # Only continue when the thumb does not exist.
337 self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
338
339 # WHEN: Create the thumb.
340 icon = create_thumb(image_path, thumb_path, size=thumb_size)
341
342 # THEN: Check if the thumb was created, retaining its aspect ratio.
343 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
344 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
345 self.assertFalse(icon.isNull(), 'The icon should not be null')
346 self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
347
348 # Remove the thumb so that the test actually tests if the thumb will be created.
349 try:
350 os.remove(thumb_path)
351 except:
352 pass
353
354 def create_thumb_width_only_test(self):
355 """
356 Test the create_thumb() function with a size of only width specified.
357 """
358 # GIVEN: An image to create a thumb of.
359 image_path = os.path.join(TEST_PATH, 'church.jpg')
360 thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
361 thumb_size = QtCore.QSize(100, -1)
362 expected_size = QtCore.QSize(100, 137)
363
364 # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
365 # last test.
366 try:
367 os.remove(thumb_path)
368 except:
369 pass
370
371 # Only continue when the thumb does not exist.
372 self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
373
374 # WHEN: Create the thumb.
375 icon = create_thumb(image_path, thumb_path, size=thumb_size)
376
377 # THEN: Check if the thumb was created, retaining its aspect ratio.
378 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
379 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
380 self.assertFalse(icon.isNull(), 'The icon should not be null')
381 self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
382
383 # Remove the thumb so that the test actually tests if the thumb will be created.
384 try:
385 os.remove(thumb_path)
386 except:
387 pass
388
389 def create_thumb_height_only_test(self):
390 """
391 Test the create_thumb() function with a size of only height specified.
392 """
393 # GIVEN: An image to create a thumb of.
394 image_path = os.path.join(TEST_PATH, 'church.jpg')
395 thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
396 thumb_size = QtCore.QSize(-1, 100)
397 expected_size = QtCore.QSize(72, 100)
398
399 # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
400 # last test.
401 try:
402 os.remove(thumb_path)
403 except:
404 pass
405
406 # Only continue when the thumb does not exist.
407 self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
408
409 # WHEN: Create the thumb.
410 icon = create_thumb(image_path, thumb_path, size=thumb_size)
411
412 # THEN: Check if the thumb was created, retaining its aspect ratio.
413 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
414 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
415 self.assertFalse(icon.isNull(), 'The icon should not be null')
416 self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
417
418 # Remove the thumb so that the test actually tests if the thumb will be created.
419 try:
420 os.remove(thumb_path)
421 except:
422 pass
423
424 def create_thumb_empty_img_test(self):
425 """
426 Test the create_thumb() function with a size of only height specified.
427 """
428 # GIVEN: An image to create a thumb of.
429 image_path = os.path.join(TEST_PATH, 'church.jpg')
430 thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
431 thumb_size = QtCore.QSize(-1, 100)
432 expected_size_1 = QtCore.QSize(88, 88)
433 expected_size_2 = QtCore.QSize(100, 100)
434
435
436 # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
437 # last test.
438 try:
439 os.remove(thumb_path)
440 except:
441 pass
442
443 # Only continue when the thumb does not exist.
444 self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
445
446 # WHEN: Create the thumb.
447 with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size:
448 mocked_size.return_value = QtCore.QSize(0, 0)
449 icon = create_thumb(image_path, thumb_path, size=None)
450
451 # THEN: Check if the thumb was created with aspect ratio of 1.
452 self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
453 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
454 self.assertFalse(icon.isNull(), 'The icon should not be null')
455 self.assertEqual(expected_size_1, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
456
457 # WHEN: Create the thumb.
458 with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size:
459 mocked_size.return_value = QtCore.QSize(0, 0)
460 icon = create_thumb(image_path, thumb_path, size=thumb_size)
461
462 # THEN: Check if the thumb was created with aspect ratio of 1.
463 self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
464 self.assertFalse(icon.isNull(), 'The icon should not be null')
465 self.assertEqual(expected_size_2, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
466
467 # Remove the thumb so that the test actually tests if the thumb will be created.
468 try:
469 os.remove(thumb_path)
470 except:
471 pass
472
285 def check_item_selected_true_test(self):473 def check_item_selected_true_test(self):
286 """474 """
287 Test that the check_item_selected() function returns True when there are selected indexes475 Test that the check_item_selected() function returns True when there are selected indexes
288476
=== modified file 'tests/functional/openlp_core_lib/test_serviceitem.py'
--- tests/functional/openlp_core_lib/test_serviceitem.py 2015-12-31 22:46:06 +0000
+++ tests/functional/openlp_core_lib/test_serviceitem.py 2016-05-16 12:42:11 +0000
@@ -244,14 +244,16 @@
244 self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')244 self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')
245 self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')245 self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
246246
247 @patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager')
247 @patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')248 @patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
248 def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path):249 def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path, mocked_image_manager):
249 """250 """
250 Test the Service Item - adding a presentation, and updating the thumb path251 Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
251 """252 """
252 # GIVEN: A service item, a mocked AppLocation and presentation data253 # GIVEN: A service item, a mocked AppLocation and presentation data
253 mocked_get_section_data_path.return_value = os.path.join('mocked', 'section', 'path')254 mocked_get_section_data_path.return_value = os.path.join('mocked', 'section', 'path')
254 service_item = ServiceItem(None)255 service_item = ServiceItem(None)
256 service_item.add_capability(ItemCapabilities.HasThumbnails)
255 service_item.has_original_files = False257 service_item.has_original_files = False
256 service_item.name = 'presentations'258 service_item.name = 'presentations'
257 presentation_name = 'test.pptx'259 presentation_name = 'test.pptx'
@@ -270,6 +272,7 @@
270 # THEN: verify that it is setup as a Command and that the frame data matches272 # THEN: verify that it is setup as a Command and that the frame data matches
271 self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')273 self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')
272 self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')274 self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
275 self.assertEqual(1, mocked_image_manager.add_image.call_count, 'image_manager should be used')
273276
274 def service_item_load_optical_media_from_service_test(self):277 def service_item_load_optical_media_from_service_test(self):
275 """278 """
276279
=== modified file 'tests/functional/openlp_core_ui/test_slidecontroller.py'
--- tests/functional/openlp_core_ui/test_slidecontroller.py 2016-02-27 14:25:31 +0000
+++ tests/functional/openlp_core_ui/test_slidecontroller.py 2016-05-16 12:42:11 +0000
@@ -26,7 +26,7 @@
2626
27from unittest import TestCase27from unittest import TestCase
28from openlp.core import Registry28from openlp.core import Registry
29from openlp.core.lib import ServiceItemAction29from openlp.core.lib import ImageSource, ServiceItemAction
30from openlp.core.ui import SlideController, LiveController, PreviewController30from openlp.core.ui import SlideController, LiveController, PreviewController
31from openlp.core.ui.slidecontroller import InfoLabel, WIDE_MENU, NON_TEXT_MENU31from openlp.core.ui.slidecontroller import InfoLabel, WIDE_MENU, NON_TEXT_MENU
3232
@@ -713,6 +713,175 @@
713 slide_controller.theme_screen, slide_controller.blank_screen713 slide_controller.theme_screen, slide_controller.blank_screen
714 ])714 ])
715715
716 @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
717 @patch(u'PyQt5.QtCore.QTimer.singleShot')
718 def update_preview_test_live(self, mocked_singleShot, mocked_image_manager):
719 """
720 Test that the preview screen is updated with a screen grab for live service items
721 """
722 # GIVEN: A mocked live service item, a mocked image_manager, a mocked Registry,
723 # and a slide controller with many mocks.
724 # Mocked Live Item
725 mocked_live_item = MagicMock()
726 mocked_live_item.get_rendered_frame.return_value = ''
727 mocked_live_item.is_capable = MagicMock()
728 mocked_live_item.is_capable.side_effect = [True, True]
729 # Mock image_manager
730 mocked_image_manager.get_image.return_value = QtGui.QImage()
731 # Mock Registry
732 Registry.create()
733 mocked_main_window = MagicMock()
734 Registry().register('main_window', mocked_main_window)
735 # Mock SlideController
736 slide_controller = SlideController(None)
737 slide_controller.service_item = mocked_live_item
738 slide_controller.is_live = True
739 slide_controller.log_debug = MagicMock()
740 slide_controller.selected_row = MagicMock()
741 slide_controller.screens = MagicMock()
742 slide_controller.screens.current = {'primary': ''}
743 slide_controller.display = MagicMock()
744 slide_controller.display.preview.return_value = QtGui.QImage()
745 slide_controller.grab_maindisplay = MagicMock()
746 slide_controller.slide_preview = MagicMock()
747 slide_controller.slide_count = 0
748
749 # WHEN: update_preview is called
750 slide_controller.update_preview()
751
752 # THEN: A screen_grab should have been called
753 self.assertEqual(0, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should not be called')
754 self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called')
755 self.assertEqual(2, mocked_singleShot.call_count,
756 'Timer to grab_maindisplay should have been called 2 times')
757 self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager not be called')
758
759 @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
760 @patch(u'PyQt5.QtCore.QTimer.singleShot')
761 def update_preview_test_pres(self, mocked_singleShot, mocked_image_manager):
762 """
763 Test that the preview screen is updated with the correct preview for presentation service items
764 """
765 # GIVEN: A mocked presentation service item, a mocked image_manager, a mocked Registry,
766 # and a slide controller with many mocks.
767 # Mocked Presentation Item
768 mocked_pres_item = MagicMock()
769 mocked_pres_item.get_rendered_frame.return_value = ''
770 mocked_pres_item.is_capable = MagicMock()
771 mocked_pres_item.is_capable.side_effect = [True, True]
772 # Mock image_manager
773 mocked_image_manager.get_image.return_value = QtGui.QImage()
774 # Mock Registry
775 Registry.create()
776 mocked_main_window = MagicMock()
777 Registry().register('main_window', mocked_main_window)
778 # Mock SlideController
779 slide_controller = SlideController(None)
780 slide_controller.service_item = mocked_pres_item
781 slide_controller.is_live = False
782 slide_controller.log_debug = MagicMock()
783 slide_controller.selected_row = MagicMock()
784 slide_controller.screens = MagicMock()
785 slide_controller.screens.current = {'primary': ''}
786 slide_controller.display = MagicMock()
787 slide_controller.display.preview.return_value = QtGui.QImage()
788 slide_controller.grab_maindisplay = MagicMock()
789 slide_controller.slide_preview = MagicMock()
790 slide_controller.slide_count = 0
791
792 # WHEN: update_preview is called
793 slide_controller.update_preview()
794
795 # THEN: setPixmap and the image_manager should have been called
796 self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called')
797 self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called')
798 self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called')
799 self.assertEqual(1, mocked_image_manager.get_image.call_count, 'image_manager should be called')
800
801 @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
802 @patch(u'PyQt5.QtCore.QTimer.singleShot')
803 def update_preview_test_media(self, mocked_singleShot, mocked_image_manager):
804 """
805 Test that the preview screen is updated with the correct preview for media service items
806 """
807 # GIVEN: A mocked media service item, a mocked image_manager, a mocked Registry,
808 # and a slide controller with many mocks.
809 # Mocked Media Item
810 mocked_media_item = MagicMock()
811 mocked_media_item.get_rendered_frame.return_value = ''
812 mocked_media_item.is_capable = MagicMock()
813 mocked_media_item.is_capable.side_effect = [True, False]
814 # Mock image_manager
815 mocked_image_manager.get_image.return_value = QtGui.QImage()
816 # Mock Registry
817 Registry.create()
818 mocked_main_window = MagicMock()
819 Registry().register('main_window', mocked_main_window)
820 # Mock SlideController
821 slide_controller = SlideController(None)
822 slide_controller.service_item = mocked_media_item
823 slide_controller.is_live = False
824 slide_controller.log_debug = MagicMock()
825 slide_controller.selected_row = MagicMock()
826 slide_controller.screens = MagicMock()
827 slide_controller.screens.current = {'primary': ''}
828 slide_controller.display = MagicMock()
829 slide_controller.display.preview.return_value = QtGui.QImage()
830 slide_controller.grab_maindisplay = MagicMock()
831 slide_controller.slide_preview = MagicMock()
832 slide_controller.slide_count = 0
833
834 # WHEN: update_preview is called
835 slide_controller.update_preview()
836
837 # THEN: setPixmap should have been called
838 self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called')
839 self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called')
840 self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called')
841 self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager should not be called')
842
843 @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
844 @patch(u'PyQt5.QtCore.QTimer.singleShot')
845 def update_preview_test_image(self, mocked_singleShot, mocked_image_manager):
846 """
847 Test that the preview screen is updated with the correct preview for image service items
848 """
849 # GIVEN: A mocked image service item, a mocked image_manager, a mocked Registry,
850 # and a slide controller with many mocks.
851 # Mocked Image Item
852 mocked_img_item = MagicMock()
853 mocked_img_item.get_rendered_frame.return_value = ''
854 mocked_img_item.is_capable = MagicMock()
855 mocked_img_item.is_capable.side_effect = [False, True]
856 # Mock image_manager
857 mocked_image_manager.get_image.return_value = QtGui.QImage()
858 # Mock Registry
859 Registry.create()
860 mocked_main_window = MagicMock()
861 Registry().register('main_window', mocked_main_window)
862 # Mock SlideController
863 slide_controller = SlideController(None)
864 slide_controller.service_item = mocked_img_item
865 slide_controller.is_live = False
866 slide_controller.log_debug = MagicMock()
867 slide_controller.selected_row = MagicMock()
868 slide_controller.screens = MagicMock()
869 slide_controller.screens.current = {'primary': ''}
870 slide_controller.display = MagicMock()
871 slide_controller.display.preview.return_value = QtGui.QImage()
872 slide_controller.grab_maindisplay = MagicMock()
873 slide_controller.slide_preview = MagicMock()
874 slide_controller.slide_count = 0
875
876 # WHEN: update_preview is called
877 slide_controller.update_preview()
878
879 # THEN: setPixmap and display.preview should have been called
880 self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called')
881 self.assertEqual(1, slide_controller.display.preview.call_count, 'display.preview() should be called')
882 self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called')
883 self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager should not be called')
884
716885
717class TestInfoLabel(TestCase):886class TestInfoLabel(TestCase):
718887
719888
=== modified file 'tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py'
--- tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py 2016-04-22 18:35:23 +0000
+++ tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py 2016-05-16 12:42:11 +0000
@@ -24,9 +24,11 @@
24"""24"""
25from unittest import TestCase25from unittest import TestCase
2626
27from PyQt5 import QtGui
28
27from openlp.core.common import Settings29from openlp.core.common import Settings
28from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget30from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget
29from openlp.core.lib import ServiceItem31from openlp.core.lib import ImageSource, ServiceItem
3032
31from tests.functional import MagicMock, patch, call33from tests.functional import MagicMock, patch, call
3234
@@ -72,6 +74,53 @@
72 self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')74 self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
73 self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called')75 self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called')
7476
77 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.image_manager')
78 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
79 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
80 def replace_service_item_test_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents,
81 mocked_image_manager):
82 """
83 Test that thubmails for different slides are loaded properly in replace_service_item.
84 """
85 # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
86 # different ServiceItem(s), an ImageManager, and a ListPreviewWidget.
87
88 # Mock Settings().value('advanced/slide max height')
89 self.mocked_Settings_obj.value.return_value = 0
90 # Mock self.viewport().width()
91 self.mocked_viewport_obj.width.return_value = 200
92 # Mock Image service item
93 mocked_img_service_item = MagicMock()
94 mocked_img_service_item.is_text.return_value = False
95 mocked_img_service_item.is_media.return_value = False
96 mocked_img_service_item.is_command.return_value = False
97 mocked_img_service_item.is_capable.return_value = False
98 mocked_img_service_item.get_frames.return_value = [{'title': None, 'path': 'TEST1', 'image': 'FAIL'},
99 {'title': None, 'path': 'TEST2', 'image': 'FAIL'}]
100 # Mock Command service item
101 mocked_cmd_service_item = MagicMock()
102 mocked_cmd_service_item.is_text.return_value = False
103 mocked_cmd_service_item.is_media.return_value = False
104 mocked_cmd_service_item.is_command.return_value = True
105 mocked_cmd_service_item.is_capable.return_value = True
106 mocked_cmd_service_item.get_frames.return_value = [{'title': None, 'path': 'FAIL', 'image': 'TEST3'},
107 {'title': None, 'path': 'FAIL', 'image': 'TEST4'}]
108 # Mock image_manager
109 mocked_image_manager.get_image.return_value = QtGui.QImage()
110
111 # init ListPreviewWidget and load service item
112 list_preview_widget = ListPreviewWidget(None, 1)
113
114 # WHEN: replace_service_item is called
115 list_preview_widget.replace_service_item(mocked_img_service_item, 200, 0)
116 list_preview_widget.replace_service_item(mocked_cmd_service_item, 200, 0)
117
118 # THEN: The ImageManager should be called in the appriopriate manner for each service item.
119 self.assertEquals(mocked_image_manager.get_image.call_count, 4, 'Should be called once for each slide')
120 calls = [call('TEST1', ImageSource.ImagePlugin), call('TEST2', ImageSource.ImagePlugin),
121 call('TEST3', ImageSource.CommandPlugins), call('TEST4', ImageSource.CommandPlugins)]
122 mocked_image_manager.get_image.assert_has_calls(calls)
123
75 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')124 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
76 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')125 @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
77 def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents):126 def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents):
@@ -120,6 +169,7 @@
120 # Mock image service item169 # Mock image service item
121 service_item = MagicMock()170 service_item = MagicMock()
122 service_item.is_text.return_value = False171 service_item.is_text.return_value = False
172 service_item.is_capable.return_value = False
123 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},173 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
124 {'title': None, 'path': None, 'image': None}]174 {'title': None, 'path': None, 'image': None}]
125 # init ListPreviewWidget and load service item175 # init ListPreviewWidget and load service item
@@ -156,6 +206,7 @@
156 # Mock image service item206 # Mock image service item
157 service_item = MagicMock()207 service_item = MagicMock()
158 service_item.is_text.return_value = False208 service_item.is_text.return_value = False
209 service_item.is_capable.return_value = False
159 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},210 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
160 {'title': None, 'path': None, 'image': None}]211 {'title': None, 'path': None, 'image': None}]
161 # init ListPreviewWidget and load service item212 # init ListPreviewWidget and load service item
@@ -225,6 +276,7 @@
225 # Mock image service item276 # Mock image service item
226 service_item = MagicMock()277 service_item = MagicMock()
227 service_item.is_text.return_value = False278 service_item.is_text.return_value = False
279 service_item.is_capable.return_value = False
228 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},280 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
229 {'title': None, 'path': None, 'image': None}]281 {'title': None, 'path': None, 'image': None}]
230 # Mock self.cellWidget().children().setMaximumWidth()282 # Mock self.cellWidget().children().setMaximumWidth()
@@ -261,6 +313,7 @@
261 # Mock image service item313 # Mock image service item
262 service_item = MagicMock()314 service_item = MagicMock()
263 service_item.is_text.return_value = False315 service_item.is_text.return_value = False
316 service_item.is_capable.return_value = False
264 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},317 service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
265 {'title': None, 'path': None, 'image': None}]318 {'title': None, 'path': None, 'image': None}]
266 # Mock self.cellWidget().children().setMaximumWidth()319 # Mock self.cellWidget().children().setMaximumWidth()