Merge lp:~knightrider0xd/openlp/preview-shows-live-fix-1080596 into lp:openlp
- preview-shows-live-fix-1080596
- Merge into trunk
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 |
Related bugs: |
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.
Commit message
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:/
[SUCCESS] https:/
Failing interface & coverage tests due to issue with unrelated crosswalk import module.
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Raoul Snyman (raoul-snyman) wrote : | # |
Looks OK to me.
Tim Bentley (trb143) : | # |
Preview Diff
1 | === modified file 'openlp/core/lib/__init__.py' |
2 | --- openlp/core/lib/__init__.py 2016-04-23 19:28:52 +0000 |
3 | +++ openlp/core/lib/__init__.py 2016-05-16 12:42:11 +0000 |
4 | @@ -55,9 +55,13 @@ |
5 | |
6 | ``Theme`` |
7 | This says, that the image is used by a theme. |
8 | + |
9 | + ``CommandPlugins`` |
10 | + This states that an image is being used by a command plugin. |
11 | """ |
12 | ImagePlugin = 1 |
13 | Theme = 2 |
14 | + CommandPlugins = 3 |
15 | |
16 | |
17 | class MediaType(object): |
18 | @@ -174,10 +178,30 @@ |
19 | ext = os.path.splitext(thumb_path)[1].lower() |
20 | reader = QtGui.QImageReader(image_path) |
21 | if size is None: |
22 | - ratio = reader.size().width() / reader.size().height() |
23 | + # No size given; use default height of 88 |
24 | + if reader.size().isEmpty(): |
25 | + ratio = 1 |
26 | + else: |
27 | + ratio = reader.size().width() / reader.size().height() |
28 | reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88)) |
29 | - else: |
30 | + elif size.isValid(): |
31 | + # Complete size given |
32 | reader.setScaledSize(size) |
33 | + else: |
34 | + # Invalid size given |
35 | + if reader.size().isEmpty(): |
36 | + ratio = 1 |
37 | + else: |
38 | + ratio = reader.size().width() / reader.size().height() |
39 | + if size.width() >= 0: |
40 | + # Valid width; scale height |
41 | + reader.setScaledSize(QtCore.QSize(size.width(), int(size.width() / ratio))) |
42 | + elif size.height() >= 0: |
43 | + # Valid height; scale width |
44 | + reader.setScaledSize(QtCore.QSize(int(ratio * size.height()), size.height())) |
45 | + else: |
46 | + # Invalid; use default height of 88 |
47 | + reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88)) |
48 | thumb = reader.read() |
49 | thumb.save(thumb_path, ext[1:]) |
50 | if not return_icon: |
51 | |
52 | === modified file 'openlp/core/lib/serviceitem.py' |
53 | --- openlp/core/lib/serviceitem.py 2016-02-14 17:53:16 +0000 |
54 | +++ openlp/core/lib/serviceitem.py 2016-05-16 12:42:11 +0000 |
55 | @@ -334,6 +334,8 @@ |
56 | file_location_hash, ntpath.basename(image)) |
57 | self._raw_frames.append({'title': file_name, 'image': image, 'path': path, |
58 | 'display_title': display_title, 'notes': notes}) |
59 | + if self.is_capable(ItemCapabilities.HasThumbnails): |
60 | + self.image_manager.add_image(image, ImageSource.CommandPlugins, '#000000') |
61 | self._new_item() |
62 | |
63 | def get_service_repr(self, lite_save): |
64 | |
65 | === modified file 'openlp/core/ui/lib/listpreviewwidget.py' |
66 | --- openlp/core/ui/lib/listpreviewwidget.py 2016-04-22 18:32:59 +0000 |
67 | +++ openlp/core/ui/lib/listpreviewwidget.py 2016-05-16 12:42:11 +0000 |
68 | @@ -27,7 +27,7 @@ |
69 | from PyQt5 import QtCore, QtGui, QtWidgets |
70 | |
71 | from openlp.core.common import RegistryProperties, Settings |
72 | -from openlp.core.lib import ImageSource, ServiceItem |
73 | +from openlp.core.lib import ImageSource, ItemCapabilities, ServiceItem |
74 | |
75 | |
76 | class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): |
77 | @@ -152,14 +152,16 @@ |
78 | else: |
79 | label.setScaledContents(True) |
80 | if self.service_item.is_command(): |
81 | - pixmap = QtGui.QPixmap(frame['image']) |
82 | - pixmap.setDevicePixelRatio(label.devicePixelRatio()) |
83 | - label.setPixmap(pixmap) |
84 | + if self.service_item.is_capable(ItemCapabilities.HasThumbnails): |
85 | + image = self.image_manager.get_image(frame['image'], ImageSource.CommandPlugins) |
86 | + pixmap = QtGui.QPixmap.fromImage(image) |
87 | + else: |
88 | + pixmap = QtGui.QPixmap(frame['image']) |
89 | else: |
90 | image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin) |
91 | pixmap = QtGui.QPixmap.fromImage(image) |
92 | - pixmap.setDevicePixelRatio(label.devicePixelRatio()) |
93 | - label.setPixmap(pixmap) |
94 | + pixmap.setDevicePixelRatio(label.devicePixelRatio()) |
95 | + label.setPixmap(pixmap) |
96 | slide_height = width // self.screen_ratio |
97 | # Setup and validate row height cap if in use. |
98 | max_img_row_height = Settings().value('advanced/slide max height') |
99 | |
100 | === modified file 'openlp/core/ui/slidecontroller.py' |
101 | --- openlp/core/ui/slidecontroller.py 2016-04-22 18:32:45 +0000 |
102 | +++ openlp/core/ui/slidecontroller.py 2016-05-16 12:42:11 +0000 |
103 | @@ -1135,9 +1135,21 @@ |
104 | """ |
105 | self.log_debug('update_preview %s ' % self.screens.current['primary']) |
106 | if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): |
107 | - # Grab now, but try again in a couple of seconds if slide change is slow |
108 | - QtCore.QTimer.singleShot(500, self.grab_maindisplay) |
109 | - QtCore.QTimer.singleShot(2500, self.grab_maindisplay) |
110 | + if self.is_live: |
111 | + # If live, grab screen-cap of main display now |
112 | + QtCore.QTimer.singleShot(500, self.grab_maindisplay) |
113 | + # but take another in a couple of seconds in case slide change is slow |
114 | + QtCore.QTimer.singleShot(2500, self.grab_maindisplay) |
115 | + else: |
116 | + # If not live, use the slide's thumbnail/icon instead |
117 | + image_path = self.service_item.get_rendered_frame(self.selected_row) |
118 | + if self.service_item.is_capable(ItemCapabilities.HasThumbnails): |
119 | + image = self.image_manager.get_image(image_path, ImageSource.CommandPlugins) |
120 | + self.slide_image = QtGui.QPixmap.fromImage(image) |
121 | + else: |
122 | + self.slide_image = QtGui.QPixmap(image_path) |
123 | + self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio()) |
124 | + self.slide_preview.setPixmap(self.slide_image) |
125 | else: |
126 | self.slide_image = self.display.preview() |
127 | self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio()) |
128 | |
129 | === modified file 'openlp/plugins/presentations/lib/presentationcontroller.py' |
130 | --- openlp/plugins/presentations/lib/presentationcontroller.py 2015-12-31 22:46:06 +0000 |
131 | +++ openlp/plugins/presentations/lib/presentationcontroller.py 2016-05-16 12:42:11 +0000 |
132 | @@ -242,13 +242,13 @@ |
133 | |
134 | def convert_thumbnail(self, file, idx): |
135 | """ |
136 | - Convert the slide image the application made to a standard 320x240 .png image. |
137 | + Convert the slide image the application made to a scaled 360px height .png image. |
138 | """ |
139 | if self.check_thumbnails(): |
140 | return |
141 | if os.path.isfile(file): |
142 | thumb_path = self.get_thumbnail_path(idx, False) |
143 | - create_thumb(file, thumb_path, False, QtCore.QSize(320, 240)) |
144 | + create_thumb(file, thumb_path, False, QtCore.QSize(-1, 360)) |
145 | |
146 | def get_thumbnail_path(self, slide_no, check_exists): |
147 | """ |
148 | |
149 | === modified file 'tests/functional/openlp_core_lib/test_lib.py' |
150 | --- tests/functional/openlp_core_lib/test_lib.py 2015-12-31 22:46:06 +0000 |
151 | +++ tests/functional/openlp_core_lib/test_lib.py 2016-05-16 12:42:11 +0000 |
152 | @@ -250,7 +250,7 @@ |
153 | |
154 | def create_thumb_with_size_test(self): |
155 | """ |
156 | - Test the create_thumb() function |
157 | + Test the create_thumb() function with a given size. |
158 | """ |
159 | # GIVEN: An image to create a thumb of. |
160 | image_path = os.path.join(TEST_PATH, 'church.jpg') |
161 | @@ -270,7 +270,7 @@ |
162 | # WHEN: Create the thumb. |
163 | icon = create_thumb(image_path, thumb_path, size=thumb_size) |
164 | |
165 | - # THEN: Check if the thumb was created. |
166 | + # THEN: Check if the thumb was created and scaled to the given size. |
167 | self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists') |
168 | self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
169 | self.assertFalse(icon.isNull(), 'The icon should not be null') |
170 | @@ -282,6 +282,194 @@ |
171 | except: |
172 | pass |
173 | |
174 | + def create_thumb_no_size_test(self): |
175 | + """ |
176 | + Test the create_thumb() function with no size specified. |
177 | + """ |
178 | + # GIVEN: An image to create a thumb of. |
179 | + image_path = os.path.join(TEST_PATH, 'church.jpg') |
180 | + thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg') |
181 | + expected_size = QtCore.QSize(63, 88) |
182 | + |
183 | + # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the |
184 | + # last test. |
185 | + try: |
186 | + os.remove(thumb_path) |
187 | + except: |
188 | + pass |
189 | + |
190 | + # Only continue when the thumb does not exist. |
191 | + self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.') |
192 | + |
193 | + # WHEN: Create the thumb. |
194 | + icon = create_thumb(image_path, thumb_path) |
195 | + |
196 | + # THEN: Check if the thumb was created, retaining its aspect ratio. |
197 | + self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists') |
198 | + self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
199 | + self.assertFalse(icon.isNull(), 'The icon should not be null') |
200 | + self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size') |
201 | + |
202 | + # Remove the thumb so that the test actually tests if the thumb will be created. |
203 | + try: |
204 | + os.remove(thumb_path) |
205 | + except: |
206 | + pass |
207 | + |
208 | + def create_thumb_invalid_size_test(self): |
209 | + """ |
210 | + Test the create_thumb() function with invalid size specified. |
211 | + """ |
212 | + # GIVEN: An image to create a thumb of. |
213 | + image_path = os.path.join(TEST_PATH, 'church.jpg') |
214 | + thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg') |
215 | + thumb_size = QtCore.QSize(-1, -1) |
216 | + expected_size = QtCore.QSize(63, 88) |
217 | + |
218 | + # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the |
219 | + # last test. |
220 | + try: |
221 | + os.remove(thumb_path) |
222 | + except: |
223 | + pass |
224 | + |
225 | + # Only continue when the thumb does not exist. |
226 | + self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.') |
227 | + |
228 | + # WHEN: Create the thumb. |
229 | + icon = create_thumb(image_path, thumb_path, size=thumb_size) |
230 | + |
231 | + # THEN: Check if the thumb was created, retaining its aspect ratio. |
232 | + self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists') |
233 | + self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
234 | + self.assertFalse(icon.isNull(), 'The icon should not be null') |
235 | + self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size') |
236 | + |
237 | + # Remove the thumb so that the test actually tests if the thumb will be created. |
238 | + try: |
239 | + os.remove(thumb_path) |
240 | + except: |
241 | + pass |
242 | + |
243 | + def create_thumb_width_only_test(self): |
244 | + """ |
245 | + Test the create_thumb() function with a size of only width specified. |
246 | + """ |
247 | + # GIVEN: An image to create a thumb of. |
248 | + image_path = os.path.join(TEST_PATH, 'church.jpg') |
249 | + thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg') |
250 | + thumb_size = QtCore.QSize(100, -1) |
251 | + expected_size = QtCore.QSize(100, 137) |
252 | + |
253 | + # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the |
254 | + # last test. |
255 | + try: |
256 | + os.remove(thumb_path) |
257 | + except: |
258 | + pass |
259 | + |
260 | + # Only continue when the thumb does not exist. |
261 | + self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.') |
262 | + |
263 | + # WHEN: Create the thumb. |
264 | + icon = create_thumb(image_path, thumb_path, size=thumb_size) |
265 | + |
266 | + # THEN: Check if the thumb was created, retaining its aspect ratio. |
267 | + self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists') |
268 | + self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
269 | + self.assertFalse(icon.isNull(), 'The icon should not be null') |
270 | + self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size') |
271 | + |
272 | + # Remove the thumb so that the test actually tests if the thumb will be created. |
273 | + try: |
274 | + os.remove(thumb_path) |
275 | + except: |
276 | + pass |
277 | + |
278 | + def create_thumb_height_only_test(self): |
279 | + """ |
280 | + Test the create_thumb() function with a size of only height specified. |
281 | + """ |
282 | + # GIVEN: An image to create a thumb of. |
283 | + image_path = os.path.join(TEST_PATH, 'church.jpg') |
284 | + thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg') |
285 | + thumb_size = QtCore.QSize(-1, 100) |
286 | + expected_size = QtCore.QSize(72, 100) |
287 | + |
288 | + # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the |
289 | + # last test. |
290 | + try: |
291 | + os.remove(thumb_path) |
292 | + except: |
293 | + pass |
294 | + |
295 | + # Only continue when the thumb does not exist. |
296 | + self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.') |
297 | + |
298 | + # WHEN: Create the thumb. |
299 | + icon = create_thumb(image_path, thumb_path, size=thumb_size) |
300 | + |
301 | + # THEN: Check if the thumb was created, retaining its aspect ratio. |
302 | + self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists') |
303 | + self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
304 | + self.assertFalse(icon.isNull(), 'The icon should not be null') |
305 | + self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size') |
306 | + |
307 | + # Remove the thumb so that the test actually tests if the thumb will be created. |
308 | + try: |
309 | + os.remove(thumb_path) |
310 | + except: |
311 | + pass |
312 | + |
313 | + def create_thumb_empty_img_test(self): |
314 | + """ |
315 | + Test the create_thumb() function with a size of only height specified. |
316 | + """ |
317 | + # GIVEN: An image to create a thumb of. |
318 | + image_path = os.path.join(TEST_PATH, 'church.jpg') |
319 | + thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg') |
320 | + thumb_size = QtCore.QSize(-1, 100) |
321 | + expected_size_1 = QtCore.QSize(88, 88) |
322 | + expected_size_2 = QtCore.QSize(100, 100) |
323 | + |
324 | + |
325 | + # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the |
326 | + # last test. |
327 | + try: |
328 | + os.remove(thumb_path) |
329 | + except: |
330 | + pass |
331 | + |
332 | + # Only continue when the thumb does not exist. |
333 | + self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.') |
334 | + |
335 | + # WHEN: Create the thumb. |
336 | + with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size: |
337 | + mocked_size.return_value = QtCore.QSize(0, 0) |
338 | + icon = create_thumb(image_path, thumb_path, size=None) |
339 | + |
340 | + # THEN: Check if the thumb was created with aspect ratio of 1. |
341 | + self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists') |
342 | + self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
343 | + self.assertFalse(icon.isNull(), 'The icon should not be null') |
344 | + self.assertEqual(expected_size_1, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size') |
345 | + |
346 | + # WHEN: Create the thumb. |
347 | + with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size: |
348 | + mocked_size.return_value = QtCore.QSize(0, 0) |
349 | + icon = create_thumb(image_path, thumb_path, size=thumb_size) |
350 | + |
351 | + # THEN: Check if the thumb was created with aspect ratio of 1. |
352 | + self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') |
353 | + self.assertFalse(icon.isNull(), 'The icon should not be null') |
354 | + self.assertEqual(expected_size_2, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size') |
355 | + |
356 | + # Remove the thumb so that the test actually tests if the thumb will be created. |
357 | + try: |
358 | + os.remove(thumb_path) |
359 | + except: |
360 | + pass |
361 | + |
362 | def check_item_selected_true_test(self): |
363 | """ |
364 | Test that the check_item_selected() function returns True when there are selected indexes |
365 | |
366 | === modified file 'tests/functional/openlp_core_lib/test_serviceitem.py' |
367 | --- tests/functional/openlp_core_lib/test_serviceitem.py 2015-12-31 22:46:06 +0000 |
368 | +++ tests/functional/openlp_core_lib/test_serviceitem.py 2016-05-16 12:42:11 +0000 |
369 | @@ -244,14 +244,16 @@ |
370 | self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command') |
371 | self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match') |
372 | |
373 | + @patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager') |
374 | @patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') |
375 | - def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path): |
376 | + def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path, mocked_image_manager): |
377 | """ |
378 | - Test the Service Item - adding a presentation, and updating the thumb path |
379 | + Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager |
380 | """ |
381 | # GIVEN: A service item, a mocked AppLocation and presentation data |
382 | mocked_get_section_data_path.return_value = os.path.join('mocked', 'section', 'path') |
383 | service_item = ServiceItem(None) |
384 | + service_item.add_capability(ItemCapabilities.HasThumbnails) |
385 | service_item.has_original_files = False |
386 | service_item.name = 'presentations' |
387 | presentation_name = 'test.pptx' |
388 | @@ -270,6 +272,7 @@ |
389 | # THEN: verify that it is setup as a Command and that the frame data matches |
390 | self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command') |
391 | self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match') |
392 | + self.assertEqual(1, mocked_image_manager.add_image.call_count, 'image_manager should be used') |
393 | |
394 | def service_item_load_optical_media_from_service_test(self): |
395 | """ |
396 | |
397 | === modified file 'tests/functional/openlp_core_ui/test_slidecontroller.py' |
398 | --- tests/functional/openlp_core_ui/test_slidecontroller.py 2016-02-27 14:25:31 +0000 |
399 | +++ tests/functional/openlp_core_ui/test_slidecontroller.py 2016-05-16 12:42:11 +0000 |
400 | @@ -26,7 +26,7 @@ |
401 | |
402 | from unittest import TestCase |
403 | from openlp.core import Registry |
404 | -from openlp.core.lib import ServiceItemAction |
405 | +from openlp.core.lib import ImageSource, ServiceItemAction |
406 | from openlp.core.ui import SlideController, LiveController, PreviewController |
407 | from openlp.core.ui.slidecontroller import InfoLabel, WIDE_MENU, NON_TEXT_MENU |
408 | |
409 | @@ -713,6 +713,175 @@ |
410 | slide_controller.theme_screen, slide_controller.blank_screen |
411 | ]) |
412 | |
413 | + @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') |
414 | + @patch(u'PyQt5.QtCore.QTimer.singleShot') |
415 | + def update_preview_test_live(self, mocked_singleShot, mocked_image_manager): |
416 | + """ |
417 | + Test that the preview screen is updated with a screen grab for live service items |
418 | + """ |
419 | + # GIVEN: A mocked live service item, a mocked image_manager, a mocked Registry, |
420 | + # and a slide controller with many mocks. |
421 | + # Mocked Live Item |
422 | + mocked_live_item = MagicMock() |
423 | + mocked_live_item.get_rendered_frame.return_value = '' |
424 | + mocked_live_item.is_capable = MagicMock() |
425 | + mocked_live_item.is_capable.side_effect = [True, True] |
426 | + # Mock image_manager |
427 | + mocked_image_manager.get_image.return_value = QtGui.QImage() |
428 | + # Mock Registry |
429 | + Registry.create() |
430 | + mocked_main_window = MagicMock() |
431 | + Registry().register('main_window', mocked_main_window) |
432 | + # Mock SlideController |
433 | + slide_controller = SlideController(None) |
434 | + slide_controller.service_item = mocked_live_item |
435 | + slide_controller.is_live = True |
436 | + slide_controller.log_debug = MagicMock() |
437 | + slide_controller.selected_row = MagicMock() |
438 | + slide_controller.screens = MagicMock() |
439 | + slide_controller.screens.current = {'primary': ''} |
440 | + slide_controller.display = MagicMock() |
441 | + slide_controller.display.preview.return_value = QtGui.QImage() |
442 | + slide_controller.grab_maindisplay = MagicMock() |
443 | + slide_controller.slide_preview = MagicMock() |
444 | + slide_controller.slide_count = 0 |
445 | + |
446 | + # WHEN: update_preview is called |
447 | + slide_controller.update_preview() |
448 | + |
449 | + # THEN: A screen_grab should have been called |
450 | + self.assertEqual(0, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should not be called') |
451 | + self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called') |
452 | + self.assertEqual(2, mocked_singleShot.call_count, |
453 | + 'Timer to grab_maindisplay should have been called 2 times') |
454 | + self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager not be called') |
455 | + |
456 | + @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') |
457 | + @patch(u'PyQt5.QtCore.QTimer.singleShot') |
458 | + def update_preview_test_pres(self, mocked_singleShot, mocked_image_manager): |
459 | + """ |
460 | + Test that the preview screen is updated with the correct preview for presentation service items |
461 | + """ |
462 | + # GIVEN: A mocked presentation service item, a mocked image_manager, a mocked Registry, |
463 | + # and a slide controller with many mocks. |
464 | + # Mocked Presentation Item |
465 | + mocked_pres_item = MagicMock() |
466 | + mocked_pres_item.get_rendered_frame.return_value = '' |
467 | + mocked_pres_item.is_capable = MagicMock() |
468 | + mocked_pres_item.is_capable.side_effect = [True, True] |
469 | + # Mock image_manager |
470 | + mocked_image_manager.get_image.return_value = QtGui.QImage() |
471 | + # Mock Registry |
472 | + Registry.create() |
473 | + mocked_main_window = MagicMock() |
474 | + Registry().register('main_window', mocked_main_window) |
475 | + # Mock SlideController |
476 | + slide_controller = SlideController(None) |
477 | + slide_controller.service_item = mocked_pres_item |
478 | + slide_controller.is_live = False |
479 | + slide_controller.log_debug = MagicMock() |
480 | + slide_controller.selected_row = MagicMock() |
481 | + slide_controller.screens = MagicMock() |
482 | + slide_controller.screens.current = {'primary': ''} |
483 | + slide_controller.display = MagicMock() |
484 | + slide_controller.display.preview.return_value = QtGui.QImage() |
485 | + slide_controller.grab_maindisplay = MagicMock() |
486 | + slide_controller.slide_preview = MagicMock() |
487 | + slide_controller.slide_count = 0 |
488 | + |
489 | + # WHEN: update_preview is called |
490 | + slide_controller.update_preview() |
491 | + |
492 | + # THEN: setPixmap and the image_manager should have been called |
493 | + self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called') |
494 | + self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called') |
495 | + self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called') |
496 | + self.assertEqual(1, mocked_image_manager.get_image.call_count, 'image_manager should be called') |
497 | + |
498 | + @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') |
499 | + @patch(u'PyQt5.QtCore.QTimer.singleShot') |
500 | + def update_preview_test_media(self, mocked_singleShot, mocked_image_manager): |
501 | + """ |
502 | + Test that the preview screen is updated with the correct preview for media service items |
503 | + """ |
504 | + # GIVEN: A mocked media service item, a mocked image_manager, a mocked Registry, |
505 | + # and a slide controller with many mocks. |
506 | + # Mocked Media Item |
507 | + mocked_media_item = MagicMock() |
508 | + mocked_media_item.get_rendered_frame.return_value = '' |
509 | + mocked_media_item.is_capable = MagicMock() |
510 | + mocked_media_item.is_capable.side_effect = [True, False] |
511 | + # Mock image_manager |
512 | + mocked_image_manager.get_image.return_value = QtGui.QImage() |
513 | + # Mock Registry |
514 | + Registry.create() |
515 | + mocked_main_window = MagicMock() |
516 | + Registry().register('main_window', mocked_main_window) |
517 | + # Mock SlideController |
518 | + slide_controller = SlideController(None) |
519 | + slide_controller.service_item = mocked_media_item |
520 | + slide_controller.is_live = False |
521 | + slide_controller.log_debug = MagicMock() |
522 | + slide_controller.selected_row = MagicMock() |
523 | + slide_controller.screens = MagicMock() |
524 | + slide_controller.screens.current = {'primary': ''} |
525 | + slide_controller.display = MagicMock() |
526 | + slide_controller.display.preview.return_value = QtGui.QImage() |
527 | + slide_controller.grab_maindisplay = MagicMock() |
528 | + slide_controller.slide_preview = MagicMock() |
529 | + slide_controller.slide_count = 0 |
530 | + |
531 | + # WHEN: update_preview is called |
532 | + slide_controller.update_preview() |
533 | + |
534 | + # THEN: setPixmap should have been called |
535 | + self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called') |
536 | + self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called') |
537 | + self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called') |
538 | + self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager should not be called') |
539 | + |
540 | + @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') |
541 | + @patch(u'PyQt5.QtCore.QTimer.singleShot') |
542 | + def update_preview_test_image(self, mocked_singleShot, mocked_image_manager): |
543 | + """ |
544 | + Test that the preview screen is updated with the correct preview for image service items |
545 | + """ |
546 | + # GIVEN: A mocked image service item, a mocked image_manager, a mocked Registry, |
547 | + # and a slide controller with many mocks. |
548 | + # Mocked Image Item |
549 | + mocked_img_item = MagicMock() |
550 | + mocked_img_item.get_rendered_frame.return_value = '' |
551 | + mocked_img_item.is_capable = MagicMock() |
552 | + mocked_img_item.is_capable.side_effect = [False, True] |
553 | + # Mock image_manager |
554 | + mocked_image_manager.get_image.return_value = QtGui.QImage() |
555 | + # Mock Registry |
556 | + Registry.create() |
557 | + mocked_main_window = MagicMock() |
558 | + Registry().register('main_window', mocked_main_window) |
559 | + # Mock SlideController |
560 | + slide_controller = SlideController(None) |
561 | + slide_controller.service_item = mocked_img_item |
562 | + slide_controller.is_live = False |
563 | + slide_controller.log_debug = MagicMock() |
564 | + slide_controller.selected_row = MagicMock() |
565 | + slide_controller.screens = MagicMock() |
566 | + slide_controller.screens.current = {'primary': ''} |
567 | + slide_controller.display = MagicMock() |
568 | + slide_controller.display.preview.return_value = QtGui.QImage() |
569 | + slide_controller.grab_maindisplay = MagicMock() |
570 | + slide_controller.slide_preview = MagicMock() |
571 | + slide_controller.slide_count = 0 |
572 | + |
573 | + # WHEN: update_preview is called |
574 | + slide_controller.update_preview() |
575 | + |
576 | + # THEN: setPixmap and display.preview should have been called |
577 | + self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called') |
578 | + self.assertEqual(1, slide_controller.display.preview.call_count, 'display.preview() should be called') |
579 | + self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called') |
580 | + self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager should not be called') |
581 | + |
582 | |
583 | class TestInfoLabel(TestCase): |
584 | |
585 | |
586 | === modified file 'tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py' |
587 | --- tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py 2016-04-22 18:35:23 +0000 |
588 | +++ tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py 2016-05-16 12:42:11 +0000 |
589 | @@ -24,9 +24,11 @@ |
590 | """ |
591 | from unittest import TestCase |
592 | |
593 | +from PyQt5 import QtGui |
594 | + |
595 | from openlp.core.common import Settings |
596 | from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget |
597 | -from openlp.core.lib import ServiceItem |
598 | +from openlp.core.lib import ImageSource, ServiceItem |
599 | |
600 | from tests.functional import MagicMock, patch, call |
601 | |
602 | @@ -72,6 +74,53 @@ |
603 | self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None') |
604 | self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called') |
605 | |
606 | + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.image_manager') |
607 | + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') |
608 | + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') |
609 | + def replace_service_item_test_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents, |
610 | + mocked_image_manager): |
611 | + """ |
612 | + Test that thubmails for different slides are loaded properly in replace_service_item. |
613 | + """ |
614 | + # GIVEN: A setting to adjust "Max height for non-text slides in slide controller", |
615 | + # different ServiceItem(s), an ImageManager, and a ListPreviewWidget. |
616 | + |
617 | + # Mock Settings().value('advanced/slide max height') |
618 | + self.mocked_Settings_obj.value.return_value = 0 |
619 | + # Mock self.viewport().width() |
620 | + self.mocked_viewport_obj.width.return_value = 200 |
621 | + # Mock Image service item |
622 | + mocked_img_service_item = MagicMock() |
623 | + mocked_img_service_item.is_text.return_value = False |
624 | + mocked_img_service_item.is_media.return_value = False |
625 | + mocked_img_service_item.is_command.return_value = False |
626 | + mocked_img_service_item.is_capable.return_value = False |
627 | + mocked_img_service_item.get_frames.return_value = [{'title': None, 'path': 'TEST1', 'image': 'FAIL'}, |
628 | + {'title': None, 'path': 'TEST2', 'image': 'FAIL'}] |
629 | + # Mock Command service item |
630 | + mocked_cmd_service_item = MagicMock() |
631 | + mocked_cmd_service_item.is_text.return_value = False |
632 | + mocked_cmd_service_item.is_media.return_value = False |
633 | + mocked_cmd_service_item.is_command.return_value = True |
634 | + mocked_cmd_service_item.is_capable.return_value = True |
635 | + mocked_cmd_service_item.get_frames.return_value = [{'title': None, 'path': 'FAIL', 'image': 'TEST3'}, |
636 | + {'title': None, 'path': 'FAIL', 'image': 'TEST4'}] |
637 | + # Mock image_manager |
638 | + mocked_image_manager.get_image.return_value = QtGui.QImage() |
639 | + |
640 | + # init ListPreviewWidget and load service item |
641 | + list_preview_widget = ListPreviewWidget(None, 1) |
642 | + |
643 | + # WHEN: replace_service_item is called |
644 | + list_preview_widget.replace_service_item(mocked_img_service_item, 200, 0) |
645 | + list_preview_widget.replace_service_item(mocked_cmd_service_item, 200, 0) |
646 | + |
647 | + # THEN: The ImageManager should be called in the appriopriate manner for each service item. |
648 | + self.assertEquals(mocked_image_manager.get_image.call_count, 4, 'Should be called once for each slide') |
649 | + calls = [call('TEST1', ImageSource.ImagePlugin), call('TEST2', ImageSource.ImagePlugin), |
650 | + call('TEST3', ImageSource.CommandPlugins), call('TEST4', ImageSource.CommandPlugins)] |
651 | + mocked_image_manager.get_image.assert_has_calls(calls) |
652 | + |
653 | @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') |
654 | @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') |
655 | def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents): |
656 | @@ -120,6 +169,7 @@ |
657 | # Mock image service item |
658 | service_item = MagicMock() |
659 | service_item.is_text.return_value = False |
660 | + service_item.is_capable.return_value = False |
661 | service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None}, |
662 | {'title': None, 'path': None, 'image': None}] |
663 | # init ListPreviewWidget and load service item |
664 | @@ -156,6 +206,7 @@ |
665 | # Mock image service item |
666 | service_item = MagicMock() |
667 | service_item.is_text.return_value = False |
668 | + service_item.is_capable.return_value = False |
669 | service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None}, |
670 | {'title': None, 'path': None, 'image': None}] |
671 | # init ListPreviewWidget and load service item |
672 | @@ -225,6 +276,7 @@ |
673 | # Mock image service item |
674 | service_item = MagicMock() |
675 | service_item.is_text.return_value = False |
676 | + service_item.is_capable.return_value = False |
677 | service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None}, |
678 | {'title': None, 'path': None, 'image': None}] |
679 | # Mock self.cellWidget().children().setMaximumWidth() |
680 | @@ -261,6 +313,7 @@ |
681 | # Mock image service item |
682 | service_item = MagicMock() |
683 | service_item.is_text.return_value = False |
684 | + service_item.is_capable.return_value = False |
685 | service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None}, |
686 | {'title': None, 'path': None, 'image': None}] |
687 | # Mock self.cellWidget().children().setMaximumWidth() |
Just one clarification?