Merge lp:~tomasgroth/openlp/ppt-fixes into lp:openlp
- ppt-fixes
- Merge into trunk
Proposed by
Tomas Groth
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Raoul Snyman | ||||||||
Approved revision: | 2529 | ||||||||
Merged at revision: | 2527 | ||||||||
Proposed branch: | lp:~tomasgroth/openlp/ppt-fixes | ||||||||
Merge into: | lp:openlp | ||||||||
Diff against target: |
553 lines (+180/-65) 6 files modified
openlp/plugins/presentations/lib/impresscontroller.py (+1/-1) openlp/plugins/presentations/lib/messagelistener.py (+2/-2) openlp/plugins/presentations/lib/powerpointcontroller.py (+123/-60) openlp/plugins/presentations/lib/presentationtab.py (+25/-0) openlp/plugins/presentations/presentationplugin.py (+2/-1) tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py (+27/-1) |
||||||||
To merge this branch: | bzr merge lp:~tomasgroth/openlp/ppt-fixes | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raoul Snyman | Approve | ||
Tim Bentley | Approve | ||
Review via email: mp+255050@code.launchpad.net |
Commit message
Description of the change
Take focus back if Powerpoint steals it - fixes bug 1423913.
Optionally advance a Powerpoint slides animation when clicked in the slidecontroller - fixes bug 1194847.
Made OpenLP respect hidden slides. Improved logging in case of errors.
For Impress, go to previous effect instead of the previous slide.
To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) wrote : | # |
Revision history for this message
Raoul Snyman (raoul-snyman) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'openlp/plugins/presentations/lib/impresscontroller.py' |
2 | --- openlp/plugins/presentations/lib/impresscontroller.py 2015-01-18 13:39:21 +0000 |
3 | +++ openlp/plugins/presentations/lib/impresscontroller.py 2015-04-02 08:41:26 +0000 |
4 | @@ -428,7 +428,7 @@ |
5 | """ |
6 | Triggers the previous slide on the running presentation. |
7 | """ |
8 | - self.control.gotoPreviousSlide() |
9 | + self.control.gotoPreviousEffect() |
10 | |
11 | def get_slide_text(self, slide_no): |
12 | """ |
13 | |
14 | === modified file 'openlp/plugins/presentations/lib/messagelistener.py' |
15 | --- openlp/plugins/presentations/lib/messagelistener.py 2015-01-18 13:39:21 +0000 |
16 | +++ openlp/plugins/presentations/lib/messagelistener.py 2015-04-02 08:41:26 +0000 |
17 | @@ -93,7 +93,7 @@ |
18 | return True |
19 | if not self.doc.is_loaded(): |
20 | if not self.doc.load_presentation(): |
21 | - log.warning('Failed to activate %s' % self.doc.filepath) |
22 | + log.warning('Failed to activate %s' % self.doc.file_path) |
23 | return False |
24 | if self.is_live: |
25 | self.doc.start_presentation() |
26 | @@ -104,7 +104,7 @@ |
27 | if self.doc.is_active(): |
28 | return True |
29 | else: |
30 | - log.warning('Failed to activate %s' % self.doc.filepath) |
31 | + log.warning('Failed to activate %s' % self.doc.file_path) |
32 | return False |
33 | |
34 | def slide(self, slide): |
35 | |
36 | === modified file 'openlp/plugins/presentations/lib/powerpointcontroller.py' |
37 | --- openlp/plugins/presentations/lib/powerpointcontroller.py 2015-01-18 13:39:21 +0000 |
38 | +++ openlp/plugins/presentations/lib/powerpointcontroller.py 2015-04-02 08:41:26 +0000 |
39 | @@ -22,11 +22,14 @@ |
40 | """ |
41 | This module is for controlling powerpoint. PPT API documentation: |
42 | `http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx`_ |
43 | +2010: https://msdn.microsoft.com/en-us/library/office/ff743835%28v=office.14%29.aspx |
44 | +2013: https://msdn.microsoft.com/en-us/library/office/ff743835.aspx |
45 | """ |
46 | import os |
47 | import logging |
48 | +import time |
49 | |
50 | -from openlp.core.common import is_win |
51 | +from openlp.core.common import is_win, Settings |
52 | |
53 | if is_win(): |
54 | from win32com.client import Dispatch |
55 | @@ -36,9 +39,8 @@ |
56 | import pywintypes |
57 | |
58 | from openlp.core.lib import ScreenList |
59 | -from openlp.core.common import Registry |
60 | from openlp.core.lib.ui import UiStrings, critical_error_message_box, translate |
61 | -from openlp.core.common import trace_error_handler |
62 | +from openlp.core.common import trace_error_handler, Registry |
63 | from .presentationcontroller import PresentationController, PresentationDocument |
64 | |
65 | log = logging.getLogger(__name__) |
66 | @@ -82,6 +84,7 @@ |
67 | if not self.process: |
68 | self.process = Dispatch('PowerPoint.Application') |
69 | self.process.Visible = True |
70 | + # ppWindowMinimized = 2 |
71 | self.process.WindowState = 2 |
72 | |
73 | def kill(self): |
74 | @@ -97,8 +100,10 @@ |
75 | if self.process.Presentations.Count > 0: |
76 | return |
77 | self.process.Quit() |
78 | - except (AttributeError, pywintypes.com_error): |
79 | - pass |
80 | + except (AttributeError, pywintypes.com_error) as e: |
81 | + log.exception('Exception caught while killing powerpoint process') |
82 | + log.exception(e) |
83 | + trace_error_handler(log) |
84 | self.process = None |
85 | |
86 | |
87 | @@ -117,6 +122,8 @@ |
88 | log.debug('Init Presentation Powerpoint') |
89 | super(PowerpointDocument, self).__init__(controller, presentation) |
90 | self.presentation = None |
91 | + self.index_map = {} |
92 | + self.slide_count = 0 |
93 | |
94 | def load_presentation(self): |
95 | """ |
96 | @@ -131,16 +138,21 @@ |
97 | self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count) |
98 | self.create_thumbnails() |
99 | self.create_titles_and_notes() |
100 | - # Powerpoint 2013 pops up when loading a file, so we minimize it again |
101 | - if self.presentation.Application.Version == u'15.0': |
102 | + # Powerpoint 2010 and 2013 pops up when loading a file, so we minimize it again |
103 | + if float(self.presentation.Application.Version) >= 14.0: |
104 | try: |
105 | + # ppWindowMinimized = 2 |
106 | self.presentation.Application.WindowState = 2 |
107 | - except: |
108 | - log.error('Failed to minimize main powerpoint window') |
109 | + except (AttributeError, pywintypes.com_error) as e: |
110 | + log.exception('Failed to minimize main powerpoint window') |
111 | + log.exception(e) |
112 | trace_error_handler(log) |
113 | + # Make sure powerpoint doesn't steal focus |
114 | + Registry().get('main_window').activateWindow() |
115 | return True |
116 | - except pywintypes.com_error: |
117 | - log.error('PPT open failed') |
118 | + except (AttributeError, pywintypes.com_error) as e: |
119 | + log.exception('Exception caught while loading Powerpoint presentation') |
120 | + log.exception(e) |
121 | trace_error_handler(log) |
122 | return False |
123 | |
124 | @@ -158,9 +170,14 @@ |
125 | log.debug('create_thumbnails') |
126 | if self.check_thumbnails(): |
127 | return |
128 | + key = 1 |
129 | for num in range(self.presentation.Slides.Count): |
130 | - self.presentation.Slides(num + 1).Export( |
131 | - os.path.join(self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)), 'png', 320, 240) |
132 | + if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden: |
133 | + self.index_map[key] = num + 1 |
134 | + self.presentation.Slides(num + 1).Export( |
135 | + os.path.join(self.get_thumbnail_folder(), 'slide%d.png' % (key)), 'png', 320, 240) |
136 | + key += 1 |
137 | + self.slide_count = key - 1 |
138 | |
139 | def close_presentation(self): |
140 | """ |
141 | @@ -171,10 +188,14 @@ |
142 | if self.presentation: |
143 | try: |
144 | self.presentation.Close() |
145 | - except pywintypes.com_error: |
146 | - pass |
147 | + except (AttributeError, pywintypes.com_error) as e: |
148 | + log.exception('Caught exception while closing powerpoint presentation') |
149 | + log.exception(e) |
150 | + trace_error_handler(log) |
151 | self.presentation = None |
152 | self.controller.remove_doc(self) |
153 | + # Make sure powerpoint doesn't steal focus |
154 | + Registry().get('main_window').activateWindow() |
155 | |
156 | def is_loaded(self): |
157 | """ |
158 | @@ -188,7 +209,10 @@ |
159 | return False |
160 | if self.controller.process.Presentations.Count == 0: |
161 | return False |
162 | - except (AttributeError, pywintypes.com_error): |
163 | + except (AttributeError, pywintypes.com_error) as e: |
164 | + log.exception('Caught exception while in is_loaded') |
165 | + log.exception(e) |
166 | + trace_error_handler(log) |
167 | return False |
168 | return True |
169 | |
170 | @@ -204,7 +228,10 @@ |
171 | return False |
172 | if self.presentation.SlideShowWindow.View is None: |
173 | return False |
174 | - except (AttributeError, pywintypes.com_error): |
175 | + except (AttributeError, pywintypes.com_error) as e: |
176 | + log.exception('Caught exception while in is_active') |
177 | + log.exception(e) |
178 | + trace_error_handler(log) |
179 | return False |
180 | return True |
181 | |
182 | @@ -215,19 +242,21 @@ |
183 | log.debug('unblank_screen') |
184 | try: |
185 | self.presentation.SlideShowSettings.Run() |
186 | + # ppSlideShowRunning = 1 |
187 | self.presentation.SlideShowWindow.View.State = 1 |
188 | self.presentation.SlideShowWindow.Activate() |
189 | - if self.presentation.Application.Version == '14.0': |
190 | - # Unblanking is broken in PowerPoint 2010, need to redisplay |
191 | - slide = self.presentation.SlideShowWindow.View.CurrentShowPosition |
192 | - click = self.presentation.SlideShowWindow.View.GetClickIndex() |
193 | - self.presentation.SlideShowWindow.View.GotoSlide(slide) |
194 | - if click: |
195 | - self.presentation.SlideShowWindow.View.GotoClick(click) |
196 | - except pywintypes.com_error: |
197 | - log.error('COM error while in unblank_screen') |
198 | + # Unblanking is broken in PowerPoint 2010 and 2013, need to redisplay |
199 | + if float(self.presentation.Application.Version) >= 14.0: |
200 | + self.presentation.SlideShowWindow.View.GotoSlide(self.blank_slide, False) |
201 | + if self.blank_click: |
202 | + self.presentation.SlideShowWindow.View.GotoClick(self.blank_click) |
203 | + except (AttributeError, pywintypes.com_error) as e: |
204 | + log.exception('Caught exception while in unblank_screen') |
205 | + log.exception(e) |
206 | trace_error_handler(log) |
207 | self.show_error_msg() |
208 | + # Make sure powerpoint doesn't steal focus |
209 | + Registry().get('main_window').activateWindow() |
210 | |
211 | def blank_screen(self): |
212 | """ |
213 | @@ -235,9 +264,15 @@ |
214 | """ |
215 | log.debug('blank_screen') |
216 | try: |
217 | + # Unblanking is broken in PowerPoint 2010 and 2013, need to save info for later |
218 | + if float(self.presentation.Application.Version) >= 14.0: |
219 | + self.blank_slide = self.get_slide_number() |
220 | + self.blank_click = self.presentation.SlideShowWindow.View.GetClickIndex() |
221 | + # ppSlideShowBlackScreen = 3 |
222 | self.presentation.SlideShowWindow.View.State = 3 |
223 | - except pywintypes.com_error: |
224 | - log.error('COM error while in blank_screen') |
225 | + except (AttributeError, pywintypes.com_error) as e: |
226 | + log.exception('Caught exception while in blank_screen') |
227 | + log.exception(e) |
228 | trace_error_handler(log) |
229 | self.show_error_msg() |
230 | |
231 | @@ -248,9 +283,11 @@ |
232 | log.debug('is_blank') |
233 | if self.is_active(): |
234 | try: |
235 | + # ppSlideShowBlackScreen = 3 |
236 | return self.presentation.SlideShowWindow.View.State == 3 |
237 | - except pywintypes.com_error: |
238 | - log.error('COM error while in is_blank') |
239 | + except (AttributeError, pywintypes.com_error) as e: |
240 | + log.exception('Caught exception while in is_blank') |
241 | + log.exception(e) |
242 | trace_error_handler(log) |
243 | self.show_error_msg() |
244 | else: |
245 | @@ -263,8 +300,9 @@ |
246 | log.debug('stop_presentation') |
247 | try: |
248 | self.presentation.SlideShowWindow.View.Exit() |
249 | - except pywintypes.com_error: |
250 | - log.error('COM error while in stop_presentation') |
251 | + except (AttributeError, pywintypes.com_error) as e: |
252 | + log.exception('Caught exception while in stop_presentation') |
253 | + log.exception(e) |
254 | trace_error_handler(log) |
255 | self.show_error_msg() |
256 | |
257 | @@ -292,15 +330,19 @@ |
258 | ppt_window.Left = size.x() * 72 / dpi |
259 | ppt_window.Width = size.width() * 72 / dpi |
260 | except AttributeError as e: |
261 | - log.error('AttributeError while in start_presentation') |
262 | - log.error(e) |
263 | - # Powerpoint 2013 pops up when starting a file, so we minimize it again |
264 | - if self.presentation.Application.Version == u'15.0': |
265 | + log.exception('AttributeError while in start_presentation') |
266 | + log.exception(e) |
267 | + # Powerpoint 2010 and 2013 pops up when starting a file, so we minimize it again |
268 | + if float(self.presentation.Application.Version) >= 14.0: |
269 | try: |
270 | + # ppWindowMinimized = 2 |
271 | self.presentation.Application.WindowState = 2 |
272 | - except: |
273 | - log.error('Failed to minimize main powerpoint window') |
274 | + except (AttributeError, pywintypes.com_error) as e: |
275 | + log.exception('Failed to minimize main powerpoint window') |
276 | + log.exception(e) |
277 | trace_error_handler(log) |
278 | + # Make sure powerpoint doesn't steal focus |
279 | + Registry().get('main_window').activateWindow() |
280 | |
281 | def get_slide_number(self): |
282 | """ |
283 | @@ -309,9 +351,19 @@ |
284 | log.debug('get_slide_number') |
285 | ret = 0 |
286 | try: |
287 | - ret = self.presentation.SlideShowWindow.View.CurrentShowPosition |
288 | - except pywintypes.com_error: |
289 | - log.error('COM error while in get_slide_number') |
290 | + # We need 2 approaches to getting the current slide number, because |
291 | + # SlideShowWindow.View.Slide.SlideIndex wont work on the end-slide where Slide isn't available, and |
292 | + # SlideShowWindow.View.CurrentShowPosition returns 0 when called when a transistion is executing (in 2013) |
293 | + # So we use SlideShowWindow.View.Slide.SlideIndex unless the state is done (ppSlideShowDone = 5) |
294 | + if self.presentation.SlideShowWindow.View.State != 5: |
295 | + ret = self.presentation.SlideShowWindow.View.Slide.SlideNumber |
296 | + # Do reverse lookup in the index_map to find the slide number to return |
297 | + ret = next((key for key, slidenum in self.index_map.items() if slidenum == ret), None) |
298 | + else: |
299 | + ret = self.presentation.SlideShowWindow.View.CurrentShowPosition |
300 | + except (AttributeError, pywintypes.com_error) as e: |
301 | + log.exception('Caught exception while in get_slide_number') |
302 | + log.exception(e) |
303 | trace_error_handler(log) |
304 | self.show_error_msg() |
305 | return ret |
306 | @@ -321,14 +373,7 @@ |
307 | Returns total number of slides. |
308 | """ |
309 | log.debug('get_slide_count') |
310 | - ret = 0 |
311 | - try: |
312 | - ret = self.presentation.Slides.Count |
313 | - except pywintypes.com_error: |
314 | - log.error('COM error while in get_slide_count') |
315 | - trace_error_handler(log) |
316 | - self.show_error_msg() |
317 | - return ret |
318 | + return self.slide_count |
319 | |
320 | def goto_slide(self, slide_no): |
321 | """ |
322 | @@ -338,9 +383,19 @@ |
323 | """ |
324 | log.debug('goto_slide') |
325 | try: |
326 | - self.presentation.SlideShowWindow.View.GotoSlide(slide_no) |
327 | - except pywintypes.com_error: |
328 | - log.error('COM error while in goto_slide') |
329 | + if Settings().value('presentations/powerpoint slide click advance') \ |
330 | + and self.get_slide_number() == self.index_map[slide_no]: |
331 | + click_index = self.presentation.SlideShowWindow.View.GetClickIndex() |
332 | + click_count = self.presentation.SlideShowWindow.View.GetClickCount() |
333 | + log.debug('We are already on this slide - go to next effect if any left, idx: %d, count: %d' |
334 | + % (click_index, click_count)) |
335 | + if click_index < click_count: |
336 | + self.next_step() |
337 | + else: |
338 | + self.presentation.SlideShowWindow.View.GotoSlide(self.index_map[slide_no]) |
339 | + except (AttributeError, pywintypes.com_error) as e: |
340 | + log.exception('Caught exception while in goto_slide') |
341 | + log.exception(e) |
342 | trace_error_handler(log) |
343 | self.show_error_msg() |
344 | |
345 | @@ -351,12 +406,14 @@ |
346 | log.debug('next_step') |
347 | try: |
348 | self.presentation.SlideShowWindow.View.Next() |
349 | - except pywintypes.com_error: |
350 | - log.error('COM error while in next_step') |
351 | + except (AttributeError, pywintypes.com_error) as e: |
352 | + log.exception('Caught exception while in next_step') |
353 | + log.exception(e) |
354 | trace_error_handler(log) |
355 | self.show_error_msg() |
356 | return |
357 | if self.get_slide_number() > self.get_slide_count(): |
358 | + log.debug('past end, stepping back to previous') |
359 | self.previous_step() |
360 | |
361 | def previous_step(self): |
362 | @@ -366,8 +423,9 @@ |
363 | log.debug('previous_step') |
364 | try: |
365 | self.presentation.SlideShowWindow.View.Previous() |
366 | - except pywintypes.com_error: |
367 | - log.error('COM error while in previous_step') |
368 | + except (AttributeError, pywintypes.com_error) as e: |
369 | + log.exception('Caught exception while in previous_step') |
370 | + log.exception(e) |
371 | trace_error_handler(log) |
372 | self.show_error_msg() |
373 | |
374 | @@ -377,7 +435,7 @@ |
375 | |
376 | :param slide_no: The slide the text is required for, starting at 1 |
377 | """ |
378 | - return _get_text_from_shapes(self.presentation.Slides(slide_no).Shapes) |
379 | + return _get_text_from_shapes(self.presentation.Slides(self.index_map[slide_no]).Shapes) |
380 | |
381 | def get_slide_notes(self, slide_no): |
382 | """ |
383 | @@ -385,7 +443,7 @@ |
384 | |
385 | :param slide_no: The slide the text is required for, starting at 1 |
386 | """ |
387 | - return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes) |
388 | + return _get_text_from_shapes(self.presentation.Slides(self.index_map[slide_no]).NotesPage.Shapes) |
389 | |
390 | def create_titles_and_notes(self): |
391 | """ |
392 | @@ -396,7 +454,8 @@ |
393 | """ |
394 | titles = [] |
395 | notes = [] |
396 | - for slide in self.presentation.Slides: |
397 | + for num in range(self.get_slide_count()): |
398 | + slide = self.presentation.Slides(self.index_map[num + 1]) |
399 | try: |
400 | text = slide.Shapes.Title.TextFrame.TextRange.Text |
401 | except Exception as e: |
402 | @@ -413,7 +472,11 @@ |
403 | """ |
404 | Stop presentation and display an error message. |
405 | """ |
406 | - self.stop_presentation() |
407 | + try: |
408 | + self.presentation.SlideShowWindow.View.Exit() |
409 | + except (AttributeError, pywintypes.com_error) as e: |
410 | + log.exception('Failed to exit Powerpoint presentation after error') |
411 | + log.exception(e) |
412 | critical_error_message_box(UiStrings().Error, translate('PresentationPlugin.PowerpointDocument', |
413 | 'An error occurred in the Powerpoint integration ' |
414 | 'and the presentation will be stopped. ' |
415 | |
416 | === modified file 'openlp/plugins/presentations/lib/presentationtab.py' |
417 | --- openlp/plugins/presentations/lib/presentationtab.py 2015-01-18 13:39:21 +0000 |
418 | +++ openlp/plugins/presentations/lib/presentationtab.py 2015-04-02 08:41:26 +0000 |
419 | @@ -68,6 +68,15 @@ |
420 | self.override_app_check_box.setObjectName('override_app_check_box') |
421 | self.advanced_layout.addWidget(self.override_app_check_box) |
422 | self.left_layout.addWidget(self.advanced_group_box) |
423 | + # PowerPoint |
424 | + self.powerpoint_group_box = QtGui.QGroupBox(self.left_column) |
425 | + self.powerpoint_group_box.setObjectName('powerpoint_group_box') |
426 | + self.powerpoint_layout = QtGui.QVBoxLayout(self.powerpoint_group_box) |
427 | + self.powerpoint_layout.setObjectName('powerpoint_layout') |
428 | + self.ppt_slide_click_check_box = QtGui.QCheckBox(self.powerpoint_group_box) |
429 | + self.powerpoint_group_box.setObjectName('ppt_slide_click_check_box') |
430 | + self.powerpoint_layout.addWidget(self.ppt_slide_click_check_box) |
431 | + self.left_layout.addWidget(self.powerpoint_group_box) |
432 | # Pdf options |
433 | self.pdf_group_box = QtGui.QGroupBox(self.left_column) |
434 | self.pdf_group_box.setObjectName('pdf_group_box') |
435 | @@ -108,8 +117,12 @@ |
436 | self.set_controller_text(checkbox, controller) |
437 | self.advanced_group_box.setTitle(UiStrings().Advanced) |
438 | self.pdf_group_box.setTitle(translate('PresentationPlugin.PresentationTab', 'PDF options')) |
439 | + self.powerpoint_group_box.setTitle(translate('PresentationPlugin.PresentationTab', 'PowerPoint options')) |
440 | self.override_app_check_box.setText( |
441 | translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden')) |
442 | + self.ppt_slide_click_check_box.setText( |
443 | + translate('PresentationPlugin.PresentationTab', |
444 | + 'Clicking on a selected slide in the slidecontroller advances to next effect.')) |
445 | self.pdf_program_check_box.setText( |
446 | translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:')) |
447 | |
448 | @@ -123,11 +136,18 @@ |
449 | """ |
450 | Load the settings. |
451 | """ |
452 | + powerpoint_available = False |
453 | for key in self.controllers: |
454 | controller = self.controllers[key] |
455 | checkbox = self.presenter_check_boxes[controller.name] |
456 | checkbox.setChecked(Settings().value(self.settings_section + '/' + controller.name)) |
457 | + if controller.name == 'Powerpoint' and controller.is_available(): |
458 | + powerpoint_available = True |
459 | self.override_app_check_box.setChecked(Settings().value(self.settings_section + '/override app')) |
460 | + # Load Powerpoint settings |
461 | + self.ppt_slide_click_check_box.setChecked(Settings().value(self.settings_section + |
462 | + '/powerpoint slide click advance')) |
463 | + self.ppt_slide_click_check_box.setEnabled(powerpoint_available) |
464 | # load pdf-program settings |
465 | enable_pdf_program = Settings().value(self.settings_section + '/enable_pdf_program') |
466 | self.pdf_program_check_box.setChecked(enable_pdf_program) |
467 | @@ -161,6 +181,11 @@ |
468 | if Settings().value(setting_key) != self.override_app_check_box.checkState(): |
469 | Settings().setValue(setting_key, self.override_app_check_box.checkState()) |
470 | changed = True |
471 | + # Save powerpoint settings |
472 | + setting_key = self.settings_section + '/powerpoint slide click advance' |
473 | + if Settings().value(setting_key) != self.ppt_slide_click_check_box.checkState(): |
474 | + Settings().setValue(setting_key, self.ppt_slide_click_check_box.checkState()) |
475 | + changed = True |
476 | # Save pdf-settings |
477 | pdf_program = self.pdf_program_path.text() |
478 | enable_pdf_program = self.pdf_program_check_box.checkState() |
479 | |
480 | === modified file 'openlp/plugins/presentations/presentationplugin.py' |
481 | --- openlp/plugins/presentations/presentationplugin.py 2015-03-10 22:00:32 +0000 |
482 | +++ openlp/plugins/presentations/presentationplugin.py 2015-04-02 08:41:26 +0000 |
483 | @@ -44,7 +44,8 @@ |
484 | 'presentations/Powerpoint Viewer': QtCore.Qt.Checked, |
485 | 'presentations/Pdf': QtCore.Qt.Checked, |
486 | 'presentations/presentations files': [], |
487 | - 'presentations/thumbnail_scheme': '' |
488 | + 'presentations/thumbnail_scheme': '', |
489 | + 'presentations/powerpoint slide click advance': QtCore.Qt.Unchecked |
490 | } |
491 | |
492 | |
493 | |
494 | === modified file 'tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py' |
495 | --- tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py 2015-01-18 13:39:21 +0000 |
496 | +++ tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py 2015-04-02 08:41:26 +0000 |
497 | @@ -33,11 +33,15 @@ |
498 | |
499 | from openlp.plugins.presentations.lib.powerpointcontroller import PowerpointController, PowerpointDocument,\ |
500 | _get_text_from_shapes |
501 | -from openlp.core.common import is_win |
502 | +from openlp.core.common import is_win, Settings |
503 | |
504 | if is_win(): |
505 | import pywintypes |
506 | |
507 | +__default_settings__ = { |
508 | + 'presentations/powerpoint slide click advance': True |
509 | +} |
510 | + |
511 | |
512 | class TestPowerpointController(TestCase, TestMixin): |
513 | """ |
514 | @@ -104,6 +108,7 @@ |
515 | self.mock_presentation_document_get_temp_folder.return_value = 'temp folder' |
516 | self.file_name = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'test.pptx') |
517 | self.real_controller = PowerpointController(self.mock_plugin) |
518 | + Settings().extend_default_settings(__default_settings__) |
519 | |
520 | def tearDown(self): |
521 | """ |
522 | @@ -126,6 +131,7 @@ |
523 | instance = PowerpointDocument(self.mock_controller, self.mock_presentation) |
524 | instance.presentation = MagicMock() |
525 | instance.presentation.SlideShowWindow.View.GotoSlide = MagicMock(side_effect=pywintypes.com_error('1')) |
526 | + instance.index_map[42] = 42 |
527 | |
528 | # WHEN: Calling goto_slide which will throw an exception |
529 | instance.goto_slide(42) |
530 | @@ -227,3 +233,23 @@ |
531 | |
532 | # THEN: it should not fail but return empty string |
533 | self.assertEqual(result, '', 'result should be empty') |
534 | + |
535 | + def goto_slide_test(self): |
536 | + """ |
537 | + Test that goto_slide goes to next effect if the slide is already displayed |
538 | + """ |
539 | + # GIVEN: A Document with mocked controller, presentation, and mocked functions get_slide_number and next_step |
540 | + doc = PowerpointDocument(self.mock_controller, self.mock_presentation) |
541 | + doc.presentation = MagicMock() |
542 | + doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 1 |
543 | + doc.presentation.SlideShowWindow.View.GetClickCount.return_value = 2 |
544 | + doc.get_slide_number = MagicMock() |
545 | + doc.get_slide_number.return_value = 1 |
546 | + doc.next_step = MagicMock() |
547 | + doc.index_map[1] = 1 |
548 | + |
549 | + # WHEN: Calling goto_slide |
550 | + doc.goto_slide(1) |
551 | + |
552 | + # THEN: next_step() should be call to try to advance to the next effect. |
553 | + self.assertTrue(doc.next_step.called, 'next_step() should have been called!') |
lp:~tomasgroth/openlp/ppt-fixes (revision 2529) ci.openlp. io/job/ Branch- 01-Pull/ 999/ ci.openlp. io/job/ Branch- 02-Functional- Tests/922/ ci.openlp. io/job/ Branch- 03-Interface- Tests/864/ ci.openlp. io/job/ Branch- 04a-Windows_ Functional_ Tests/753/ ci.openlp. io/job/ Branch- 04b-Windows_ Interface_ Tests/352/ ci.openlp. io/job/ Branch- 05a-Code_ Analysis/ 487/ ci.openlp. io/job/ Branch- 05b-Test_ Coverage/ 358/
[SUCCESS] https//
[SUCCESS] https//
[SUCCESS] https//
[SUCCESS] https//
[SUCCESS] https//
[SUCCESS] https//
[SUCCESS] https//