Merge lp:~marmyshev/openlp/presentation into lp:openlp

Proposed by Dmitriy Marmyshev
Status: Rejected
Rejected by: Tim Bentley
Proposed branch: lp:~marmyshev/openlp/presentation
Merge into: lp:openlp
Diff against target: 1187 lines (+994/-20)
11 files modified
.bzrignore (+1/-0)
openlp/core/lib/pluginmanager.py (+0/-5)
openlp/core/ui/firsttimeform.py (+1/-4)
openlp/core/ui/firsttimewizard.py (+5/-11)
openlp/plugins/presentations/lib/keynotemaccontroller.py (+360/-0)
openlp/plugins/presentations/lib/powerpointmaccontroller.py (+397/-0)
openlp/plugins/presentations/lib/presentationtab.py (+14/-0)
openlp/plugins/presentations/presentationplugin.py (+12/-0)
scripts/check_dependencies.py (+18/-0)
tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py (+93/-0)
tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py (+93/-0)
To merge this branch: bzr merge lp:~marmyshev/openlp/presentation
Reviewer Review Type Date Requested Status
Raoul Snyman Needs Fixing
Tim Bentley Pending
Andreas Preikschat Pending
matysek Pending
Dmitriy Marmyshev Pending
Review via email: mp+192798@code.launchpad.net

This proposal supersedes a proposal from 2013-10-24.

Description of the change

Add support to load presentations with PowerPoint and Keynote on Mac OS X.

To post a comment you must log in.
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

Please don't commit uncommented things. Please remove lines 10+11, 86, 112 and more.

112 + #except pywintypes.com_error:
113 + except:

Don't commit the uncommented line. You should catch the generic exception (I don't know why you commented except pywintypes.com_error out). Also you should log that you cought an exception.

Line 123: Should be openlp_settings = Settings(u'openlp.org', u'OpenLP')
We use u'' for strings. And you missed the space after the comma.

Line 127: You have two spaces there (should be just one)

Line 128 (and some more): Don't use <>, rather use != for inequality.

And please add some more comments. Regards

PS: Unable to test the code here, as I don't have a MAC

review: Needs Fixing
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Will need to be approved by matysek_

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> Will need to be approved by matysek_

I will need to test it.

Could you please add the 'appscript' osx dependency to the following script?

./scripts/check_dependencies.py

Thanks

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

I tested the branch and trying to load a presentation in openlp. MS powerpoint is started with openlp.

These are the issues I get:
- when the user quits manually powerpoint before exiting openlp - powerpoint is started again after openlp exits.
- when trying to load a ppt presentation - .ppt file is loaded into powerpoint but new presentation item is not added to openlp and I get the following exception:

cat openlp_trace.txt
 --- Exception Traceback ---
Traceback (most recent call last):
  File "/Users/martin/Documents/openlp/bug-836574/openlp/core/lib/mediamanageritem.py", line 334, in onFileClick
    self.validateAndLoad(files)
  File "/Users/martin/Documents/openlp/bug-836574/openlp/core/lib/mediamanageritem.py", line 383, in validateAndLoad
    self.loadList(full_list)
  File "/Users/martin/Documents/openlp/bug-836574/openlp/plugins/presentations/lib/mediaitem.py", line 188, in loadList
    doc.load_presentation()
  File "/Users/martin/Documents/openlp/bug-836574/openlp/plugins/presentations/lib/powerpointmaccontroller.py", line 153, in load_presentation
    self.create_thumbnails()
  File "/Users/martin/Documents/openlp/bug-836574/openlp/plugins/presentations/lib/powerpointmaccontroller.py", line 175, in create_thumbnails
    for filename in os.listdir(temp_dir):
OSError: [Errno 2] No such file or directory: '/Users/martin/Library/Application Support/openlp/Data/presentations/thumbnails/Chapter08.ppt/Chapter08.ppt'

--- System information ---
Platform: Darwin-11.4.2-x86_64-i386-64bit

--- Library Versions ---
Python: 2.7.3
Qt4: 4.8.4
Phonon: 4.6.0
PyQt4: 4.9.6
QtWebkit: 534.34
SQLAlchemy: 0.7.9
SQLAlchemy Migrate: 0.7.2
BeautifulSoup: 3.2.1
lxml: 2.3.2
Chardet: 2.0.1
PyEnchant: 1.6.5
PySQLite: -
Mako: 0.7.3
pyUNO bridge: -

Revision history for this message
matysek (mzibricky) : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

Just a note: when you are ready with your changes (fixed) which were requested then resubmit your proposal (upper-left corner -> Resubmit proposal). Then the developers know that your code base is again read to be reviewed.

Keep it up :)

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

Today I tested the r2118 - the temp_dir check and relaunching ppt are fixed.

There are some other issues:

- when opening a presentation the preview of the 1st slide is not generated in openlp. Last time it was created.
- What is the use case scenario when the powerpoint should be started?
  - Should it start directly with openlp when enabled and powerpoint is installed?
  - Or start it later when .ppt file is imported?
  - now it sometimes start with openlp
  - when powerpoint is started with openlp it is put above openlp window and openlp is thus hidden
- powerpoint and openlp icon is not visible in the dock bar - last time there were visible both.
- when a .ppt file is opened and I click on the preview button - powerpoint window takes focus and is put above openlp. But then in openlp i get message like

  "The presentation /Users/martin/Downloads/lecture22.ppt is incomplete, please reload."

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Yes, matysek, the work with PPT on Mac OS is really really hard.

There are some other issues with it:
for example, if your are in slideshow mode (with presenter view) and switch
to another app - PPT hide slideshow window from second screen. or if you
send command to PPT "Next slide" or "Go to slide N" the PPT wont do this
until you activate the PPT app.
If you use "full screen" mode (without presenter view) on second screen the
PPT app change global settings of display to "Mirror displays" and after
slideshow exits the PPT app change displays back to "extention" mode.
As it seems, the behavior of PPT will be different then on Windows platform.
I also analyzed other applications (like ProPresenter, Mediashout, new
EasyWorship) they have the same issue. They solve it in two ways:
1st - convert PPT file to its own slide's format and forget about MS PPT
forever.
2nd - use MS PPT app on Mac as launched app from their app - by sending
command (as i do) to MS PPT to start slideshow with .ppt file from service
schedule. and all controlling continuing in MS PPT, after MS PPT finish
slideshow the controlling of second screen returns back to their app.

I think, the best we can do - is the 2nd way.

Almost the same is for Keynote app controller.

So, I want to change the behavior of mac-controllers and then will propose
to merge again.

On Tue, Feb 12, 2013 at 2:03 AM, matysek <email address hidden> wrote:

> Today I tested the r2118 - the temp_dir check and relaunching ppt are
> fixed.
>
> There are some other issues:
>
> - when opening a presentation the preview of the 1st slide is not
> generated in openlp. Last time it was created.
> - What is the use case scenario when the powerpoint should be started?
> - Should it start directly with openlp when enabled and powerpoint is
> installed?
> - Or start it later when .ppt file is imported?
> - now it sometimes start with openlp
> - when powerpoint is started with openlp it is put above openlp window
> and openlp is thus hidden
> - powerpoint and openlp icon is not visible in the dock bar - last time
> there were visible both.
> - when a .ppt file is opened and I click on the preview button -
> powerpoint window takes focus and is put above openlp. But then in openlp i
> get message like
>
> "The presentation /Users/martin/Downloads/lecture22.ppt is incomplete,
> please reload."
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/143389
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
Jonathan Corwin (j-corwin) wrote : Posted in a previous version of this proposal

You may have tried this, but is it possible to re-activate the PowerPoint window prior to sending the commands? There looks to be some "Activate" applescript command to do this?

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Yes, now I use "Activate()" command for changing slides in PPT, but this
looks ugly.
This is not understandable for user's mind.

And also Keynote has the same problem as PPT - if you activate another app
during slideshow it hides slideshow window from second screen.

On Wed, Feb 13, 2013 at 2:58 PM, Jonathan Corwin <email address hidden> wrote:

> You may have tried this, but is it possible to re-activate the PowerPoint
> window prior to sending the commands? There looks to be some "Activate"
> applescript command to do this?
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/143389
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

Any progress on this?

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

- You have a conflict in 'openlp/plugins/presentations/lib/presentationtab.py'

This
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
should be
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
We moved from 80 characters to 120.

Please do not add commented lines (e. g. 207, 221, ...).

review: Needs Fixing
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

If you need help or have any questions in regard to my comments feel free to ask. :)

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

Please do not do this:
55 +from appscript import *
rather do
import appscript

59 +
60 +log = logging.getLogger(__name__)
61 +
62 +class KeynoteController(PresentationController)
Before and after the "log = " should be two blank lines

106 + if self.process and len(self.process.slideshows()) > 0:
When dealing with lists do "if not my_list" instead of "if len(my_list) > 0"

387 + text = ''
391 + text += shape.TextFrame.TextRange.Text + '\n'
If not explicit wanted do not use strings; use unicode strings: u''

review: Needs Fixing
Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

I'm testing it with macoffice 2011 but:
- the macoffice is not recognized by openl
- all the presentation controllers are greyed out in properties
- in the log there is a text like

2013-03-23 13:22:37,125 presentationplugin INFO Presentations Initialising
2013-03-23 13:22:37,140 openlp.plugins.presentations.lib.keynotemaccontroller DEBUG check_available
2013-03-23 13:22:37,140 openlp.plugins.presentations.lib.impresscontroller DEBUG check_available
2013-03-23 13:22:37,141 openlp.plugins.presentations.lib.powerpointmaccontroller DEBUG check_available
2013-03-23 13:22:37,141 openlp.plugins.presentations.lib.pptviewcontroller DEBUG check_available
2013-03-23 13:22:37,142 openlp.core.ui.mediadockmanager DEBUG Inserting Presentations dock
2013-03-23 13:22:37,145 openlp.plugins.presentations.lib.keynotemaccontroller DEBUG start_process
2013-03-23 13:22:37,146 presentationplugin WARNING Failed to start controller process
2013-03-23 13:22:37,146 openlp.plugins.presentations.lib.powerpointmaccontroller DEBUG start_process
2013-03-23 13:22:37,146 presentationplugin WARNING Failed to start controller process
2013-03-23 13:22:37,148 openlp.core.lib.pluginmanager INFO Initialisation Complete for presentations

review: Needs Information
Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

It's probably not working because with our latest style fixes you replaced
  from appscript import *
with
  import appscript

However, you should then also add prefix appscript to the objects you use from that module like

  appscript.app
  appscript.k
  appscript.CantLaunchApplicationError

463 + def check_available(self):
464 + """
465 + PowerPoint is able to run on this machine
466 + """
467 + log.debug(u'check_available')
468 + return True

Is there a better way to check availability of powerpoint than only return true?
- probably try to create process by appscript.app() and catch for error appscript.ApplicationNotFoundError

When I add .ppt file to openlp and click on the 'preview'button I get message like

  'The Presentation file.ppt is incomplete, please reload.'

review: Needs Fixing
Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

I returned back the import. Probably it's temperary.
Please, try all other behaviors of controllers.

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

The presentation plugin has been disabled in other places too, you have to enable it there as well.

openlp/core/ui/firsttimeform.py
openlp/core/ui/firsttimewizard.py

(Or search for "TODO Presentation plugin is not yet working on Mac OS X." in the source).

review: Needs Fixing
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

168 + except appscript.CantLaunchApplicationError:
169 + pass
Please log that the app could not be launched.

285 + except appscript.CommandError:
286 + pass
Please log your error (u'Could not close the presentation')

299 + if len(windows) == 0:
302 + if len(slideshows) == 0:
Just do "if my_list"

304 + except:
305 + return False
Please add a log message. Probably you should log the whole exception, so it is available when debugging.

Lines 550-560: Is this code needed? If not, remove it. If you need it for "information purpose" then rather add it to the methods docs or add a comment.

Can you explain lines 607-613. "Could not create tmp dir"? There is a function (check_directory_exists) which can be used to check/create dirs.

608 + self.presentation.save(in_ = thumbnail_folder, as_ = appscript.k.save_as_PNG)
Should be self.presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG)
(No spaces around the "=" sign after keyword arguments.)

837 + text = u''
838 + for idx in range(len(shapes)):
839 + shape = shapes[idx + 1]
840 + if shape.has_text_frame():
841 + text += shape.text_frame.text_range.content() + '\n'
842 + return text
Better do:
return u'\n'.join([shape.text_frame.text_range.content() for shape in shapes if shape.has_text_frame()])
But please test if it works, I haven't tested it. Also your function has a '\n' at the end (mine does not), is this wanted?

913 + u'PresentationModeUseSecondary': u'',
914 + u'PresentationModeEnableFeedbackDisplay': False,
915 + u'PresentationModePlayWellWithOthers': False,
What are these needed for? Why do they not follow the section/key_name conversion?

Thanks for your code, if you have any questions to my comment feel free to contact me (see my profile, or just ask here). I don't want to scare you off, but we have to make sure that the code works as best as possible (we have hardly any MAC devs and the presentation plugin was always a bit our sorrow plugin ;) ).

review: Needs Fixing
Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

299 + if len(windows) == 0:
302 + if len(slideshows) == 0:
> Just do "if my_list"

windows could be not "None" but could has 0 items and "if windows:" returns true - because of appscript reference.

550-560 - I still didnt decide how to solve the probleme of changing settins by user. This is in progress.

607-613: PPT for mac when you save slides as PNG creates dir for slides with same name as file name if the full path of presentation contains non-latin symbols. Probably it's not needed to log, but the algorithm support current work of MS PPT.

837-842: I dont know why this subs are exist in controllers for Windows PPT. I just added the same for support. I didnt find any references to this in other code.

913-915: is needed for setting up values for Keynote. this is because Core devs has changes Settins() system. I need this just in keynotecontroller, may be you could advise how to place it there and append to __default_settings__ of the plugin? I will need to append some setting keys with the same way in pptmaccontroller.

Agree with all other comments to my code. Will fix it soon.

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

> 299 + if len(windows) == 0:
> 302 + if len(slideshows) == 0:
> > Just do "if my_list"
>
> windows could be not "None" but could has 0 items and "if windows:" returns
> true - because of appscript reference.

if not my_list:
    print('if')
else:
    print('else')
When the list is empty then this will print "if". I am not sure what you mean with "windows could not be None". (Btw, I said you should write "if my_list" which is wrong, it should be "if not my_list")

Or do you mean windows being None causing an exception being caught returning False?

> 913-915: is needed for setting up values for Keynote. this is because Core
> devs has changes Settins() system. I need this just in keynotecontroller, may
> be you could advise how to place it there and append to __default_settings__
> of the plugin? I will need to append some setting keys with the same way in
> pptmaccontroller.

Just add your settings to the dict, as you already did. Just give it decent names; please no cryptic ones ;)

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

> 299 + if len(windows) == 0:
> 302 + if len(slideshows) == 0:

I mean, that because of third part module "appscript" and because of Microsoft's coders, the varaible "windows" could be a list, sometimes could a None and sometimes could be something else (like const appscript.k.missing_value). So "if len(windows) == 0:" returns false ONLY when if windows - is a list and not empty. I think this is easier. Also Keynote always returns a list even empty list. I copied for simularity with keynote controller. May be you have better idea? Ready to use it! :)

> Just add your settings to the dict, as you already did. Just give it decent names; please no cryptic ones ;)

Sorry, What do you mean? Should I write a letter to Apple Developrers of Keynote with advise to use more dicent names for thier setting's varaibles? :) (178-193)

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

304-305 not needed to log.

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

I cannot test it properly since I cannot open a presentation file:
- when I click on 'Select a new Presentation' button, then
- 'Select Presentation(s)' dialog is opened but immediately disappears
- and there is no time to select any file in that window.
- when the powerpoint integration is disabled then the dialog does not disappear anymore and keeps opened

My guess would be that something is stealing focus of the openlp window or pyqt generates any signals that causes this dialog to disappear.

What is working:
- powerpoint is started when openlp is started
- powerpoint is stopped when openlp is stopped
- if powerpoint is disabled in openl then it is not started

review: Needs Fixing
Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

I'm not sure if the issue with the 'select presentations' dialog is specific to the osx powerpoint code or to the presentation plugin in general.

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

I didnt touch anything in the plugin. I just added new controllers.
I always used DnD and this worked fine.

Just now, I've tried to click "load new presentations" on the toolbar - and
now it doesnt works - the gialog always hides.

On Sun, Apr 7, 2013 at 12:49 AM, matysek <email address hidden> wrote:

> I'm not sure if the issue with the 'select presentations' dialog is
> specific to the osx powerpoint code or to the presentation plugin in
> general.
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/157509
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

try this:
1. launch OpenLP
2. turn off Presentation plugin
3. Quit app
4. Launch OpenLP
5. turn on Presentation plugin
6. Add some presentations for tests, using "Select presentations" dialog.

This should works for now.

On Sun, Apr 7, 2013 at 12:49 AM, matysek <email address hidden> wrote:

> I'm not sure if the issue with the 'select presentations' dialog is
> specific to the osx powerpoint code or to the presentation plugin in
> general.
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/157509
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> I didnt touch anything in the plugin. I just added new controllers.
> I always used DnD and this worked fine.

What is it DnD?

> Just now, I've tried to click "load new presentations" on the toolbar - and
> now it doesnt works - the gialog always hides.

Then this should be an issue of the presentation plugin as a whole.

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> try this:
> 1. launch OpenLP
> 2. turn off Presentation plugin
> 3. Quit app
> 4. Launch OpenLP
> 5. turn on Presentation plugin
> 6. Add some presentations for tests, using "Select presentations" dialog.
>
> This should works for now.

These instructions work.

How the integration works (MacOffice 2011):
- preview of presentation file is not generated
- when user double clicks on ppt item in openlp then a powerpoint window is opened
- the user can see the presentation in powerpoint and use directly powerpoint to control the presentation.
- powerpoint will show the presentation on second screen and thus override the openlp content on the 2nd screen
- when the user double clicks on another ppt file then another new powerpoint window is opened
- when openlp is closed then all powerpoind windows are automatically closed with openlp.

One small issue that when the user double clicks a ppt item in openlp then the error 'The presentation /filename is incomplete, please reload.'.
- this is probably caused by not generating presentation preview.

Otherwise it seems stable and working properly. I suggest merging this code.

review: Approve
Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

> What is it DnD?
>
>
DnD = Drag and Drop - actually it is from the trunk code - there is
procedure "activateDnD()" for list_view

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

> One small issue that when the user double clicks a ppt item in openlp then
> the error 'The presentation /filename is incomplete, please reload.'.
> - this is probably caused by not generating presentation preview.
>
>
Can you explane more detailly about this? Did you reload it just once and
everything become good? or this issue reproduce EVERYTIME when you add new
presentation?

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> > One small issue that when the user double clicks a ppt item in openlp then
> > the error 'The presentation /filename is incomplete, please reload.'.
> > - this is probably caused by not generating presentation preview.
> Can you explane more detailly about this? Did you reload it just once and
> everything become good? or this issue reproduce EVERYTIME when you add new
> presentation?

It is reproducible every time. How to reproduce:
- click on 'Load a new presentation'
- select a .ppt file and it will create a new item in openlp
- double click that item - the .ppt file get's loaded into powerpoint and openlp will show that message.

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

> try this:
> 1. launch OpenLP
> 2. turn off Presentation plugin
> 3. Quit app
> 4. Launch OpenLP
> 5. turn on Presentation plugin
> 6. Add some presentations for tests, using "Select presentations" dialog.

Are our users going to have to do this? If so, you need to find a solution, we can't expect our users to have to run workarounds for a bug that we should be able to fix.

review: Needs Information
Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

>
> Are our users going to have to do this? If so, you need to find a solution, we
> can't expect our users to have to run workarounds for a bug that we should be
> able to fix.

No, our users should not do that. It's just seems that this issue is not caused by Dmitriy's code but by instability of the trunk.

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Of course, no!

Who can help with this bag? Because I have no clue.

On Mon, Apr 8, 2013 at 4:10 PM, Raoul Snyman <email address hidden> wrote:

> Review: Needs Information
>
> > try this:
> > 1. launch OpenLP
> > 2. turn off Presentation plugin
> > 3. Quit app
> > 4. Launch OpenLP
> > 5. turn on Presentation plugin
> > 6. Add some presentations for tests, using "Select presentations" dialog.
>
> Are our users going to have to do this? If so, you need to find a
> solution, we can't expect our users to have to run workarounds for a bug
> that we should be able to fix.
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/157509
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> Who can help with this bag? Because I have no clue.

Are you speaking about the disappearing dialog, the error message or both?

Regarding the disappearing dialog - after I applied your instructions it seems gone - not sure what happened. I'll have to double check.

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Guys, should i do here something else for merging it?

review: Needs Resubmitting
Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> Guys, should i do here something else for merging it?

From my point of view:
- Are you able to reproduce the issue 'The presentation /file/name is incomplete, please reload.'?
  - if yes - are you able to fix it?
  - if not - I will have to look at it what' wrong
- the disappearing dialog is not directly related to your code - it should be fixed but not in this pull request

Other than that I'm fine with merging it.

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

Related bug reports: #1168495 #1168493

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

The issue 'The presentation /file/name is incomplete, please reload.' cant
be reproduce on my system because it works fine with creating icons for
presentation.
608-639 are responsible for this issue, I guess.

On Fri, Apr 12, 2013 at 9:50 PM, matysek <email address hidden> wrote:

> > Guys, should i do here something else for merging it?
>
> >From my point of view:
> - Are you able to reproduce the issue 'The presentation /file/name is
> incomplete, please reload.'?
> - if yes - are you able to fix it?
> - if not - I will have to look at it what' wrong
> - the disappearing dialog is not directly related to your code - it should
> be fixed but not in this pull request
>
> Other than that I'm fine with merging it.
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/157509
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

Ok, I will try to look at the create_thumbnails().
What documents do you use for testing?
What is your office version? 2011?

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

I use *.key, *.ppt and *.pptx documents.
I use MS Office 2011 for Mac with localized interface.
I use both latin and non-latin characters in full file names.
I use both english and translated interface of OpenLP.

and create_thumbnails() works good.

On Fri, Apr 12, 2013 at 11:17 PM, matysek <email address hidden> wrote:

> Ok, I will try to look at the create_thumbnails().
> What documents do you use for testing?
> What is your office version? 2011?
> --
> https://code.launchpad.net/~marmyshev/openlp/presentation/+merge/157509
> You are the owner of lp:~marmyshev/openlp/presentation.
>

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> I use *.key, *.ppt and *.pptx documents.
> I use MS Office 2011 for Mac with localized interface.
> I use both latin and non-latin characters in full file names.
> I use both english and translated interface of OpenLP.
>
> and create_thumbnails() works good.

The following function does not create PNG files.

  self.presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG)

The following directory and its parent directories are just empty (lecture22.ppt is the name of the presentation file)

~/Library/Application\Support/openlp/Data/presentations/thumbnails/lecture22.ppt/lecture22.ppt

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

Dmitriy,

what appscript version do you use? 1.0.o or 1.0.1?

Mine is 1.0.0.

Should I try the 1.0.1?

Could this bugfix version make a difference with generating thumbnails?

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

Are you still working on this?

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

> Are you still working on this?

We are stuck on getting the thumbnails working.
- dmitriys - osx 10.8 - working
- matysek - osx 10.7 - not working

Recently I haven'd had much time for debugging this.

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Hey Dmitriy, a lot of our users would really benefit from this feature (lots of them have asked for it), are you going to try to figure out that last bug?

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

> Hey Dmitriy, a lot of our users would really benefit from this feature (lots
> of them have asked for it), are you going to try to figure out that last bug?

+1

Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Please resubmit due to the age of this request and additionally it will need converting to Python 3 as on 1/9/2013 truck will be converted.

review: Needs Resubmitting
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

In what part of the code does the thumbnail problem lays? Lines?

review: Needs Information
Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Lines 589-628 - this is procedure to create thumbnail.

MS PPT can save all slides to PNG at ones. And used it before. But somehow this doesnt work stabale on different systems (I think global settings of showing file extentions, system language, MS Office lanuage are affecting) - thumbnail paths are different. This code i just commented.

So I was going to implement second option of PPT - to save each slide to PNG in cycle. But I still cant find solution so select current slide (or change selection) in PPT by applescript bridge (appscript module). Line 597.

Can you help with this?

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

So the problem with the current code is, that you cannot set the current slide?
And the problem with the old (commented) code is, that it does not always work?

Can you post (pastebin) the doc strings for self.presentation and the doc string of "slides".

Did you see that appscript is not developed and supported anymore? http://appscript.sourceforge.net/

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

1. yes.
2. yes.
3. they are appscript objects. Can you specify what exactly do you need? I use "Microsoft PowerPoint dictionary" in Aplle script editor to find commands to use in appscript module.
4. Yes. But it works for now, and ScriptingBridge from Python works awfull. The other problem of this was discribed upper - that MS PPT for Apple doesnt have any programm interface except apple script. Appscript is just one of briges between python and apple scriping system.

Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

> 3. they are appscript objects. Can you specify what exactly do you need? I use
> "Microsoft PowerPoint dictionary" in Aplle script editor to find commands to
> use in appscript module.
I need help(self.presentation) and help(self.presentation.slides())

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

I think now this should work well with thumbnails for PPT.

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Can anybody test this on different OSX systems?

interesting to test this:
1. on "full English lang" systems - OS is English and MS PPT is English
2. and on "not English lang at all" - OS is some other lang and MS PPT is the same.

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal
Download full text (4.2 KiB)

I get the following stacktrace when trying to run openlp from this branch:

$ python openlp.py
WARNING: bool Phonon::FactoryPrivate::createBackend() phonon backend plugin could not be loaded
Traceback (most recent call last):
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 937, in emit
    msg = self.format(record)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 808, in format
    return fmt.format(record)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 554, in format
    record.exc_text = self.formatException(record.exc_info)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 504, in formatException
    traceback.print_exception(ei[0], ei[1], tb, None, sio)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/traceback.py", line 156, in print_exception
    for value, tb in values:
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/traceback.py", line 122, in _iter_chain
    context = exc.__context__
AttributeError: 'NoneType' object has no attribute '__context__'
Logged from file __init__.py, line 186
Error in sys.excepthook:
RuntimeError: super-class __init__() of type ExceptionForm was never called

Original exception was:
Traceback (most recent call last):
  File "openlp.py", line 45, in <module>
    main()
  File "/Users/martin/Projects/openlp/presentation/openlp/core/__init__.py", line 326, in main
    sys.exit(application.run(qt_args))
  File "/Users/martin/Projects/openlp/presentation/openlp/core/__init__.py", line 137, in run
    Registry().execute('bootstrap_initialise')
  File "/Users/martin/Projects/openlp/presentation/openlp/core/lib/registry.py", line 159, in execute
    result = function(*args, **kwargs)
  File "/Users/martin/Projects/openlp/presentation/openlp/core/lib/pluginmanager.py", line 86, in bootstrap_initialise
    self.initialise_plugins()
  File "/Users/martin/Projects/openlp/presentation/openlp/core/lib/pluginmanager.py", line 201, in initialise_plugins
    plugin.initialise()
  File "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/presentationplugin.py", line 91, in initialise
    super(PresentationPlugin, self).initialise()
  File "/Users/martin/Projects/openlp/presentation/openlp/core/lib/plugin.py", line 296, in initialise
    self.media_item.initialise()
  File "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/lib/mediaitem.py", line 127, in initialise
    self.populate_display_types()
  File "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/lib/mediaitem.py", line 137, in populate_display_types
    if self.controllers[item].enabled():
  File "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/lib/presentationcontroller.py", line 380, in enabled
    return self.is_available()
  File "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/lib/presentationcontroller.py", line 386, ...

Read more...

review: Needs Information
Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal
Download full text (4.8 KiB)

Do you have appscript for Python 3.3? afrter I have installed Py-33 env - I
re-install appscript 1.0.1 for python33
And do you have MS PPT 2011 on mac?

Because self.check_available() works fine on my system.

On Fri, Sep 20, 2013 at 2:02 AM, matysek <email address hidden> wrote:

> Review: Needs Information
>
> I get the following stacktrace when trying to run openlp from this branch:
>
> $ python openlp.py
> WARNING: bool Phonon::FactoryPrivate::createBackend() phonon backend
> plugin could not be loaded
> Traceback (most recent call last):
> File
> "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py",
> line 937, in emit
> msg = self.format(record)
> File
> "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py",
> line 808, in format
> return fmt.format(record)
> File
> "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py",
> line 554, in format
> record.exc_text = self.formatException(record.exc_info)
> File
> "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py",
> line 504, in formatException
> traceback.print_exception(ei[0], ei[1], tb, None, sio)
> File
> "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/traceback.py",
> line 156, in print_exception
> for value, tb in values:
> File
> "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/traceback.py",
> line 122, in _iter_chain
> context = exc.__context__
> AttributeError: 'NoneType' object has no attribute '__context__'
> Logged from file __init__.py, line 186
> Error in sys.excepthook:
> RuntimeError: super-class __init__() of type ExceptionForm was never called
>
> Original exception was:
> Traceback (most recent call last):
> File "openlp.py", line 45, in <module>
> main()
> File
> "/Users/martin/Projects/openlp/presentation/openlp/core/__init__.py", line
> 326, in main
> sys.exit(application.run(qt_args))
> File
> "/Users/martin/Projects/openlp/presentation/openlp/core/__init__.py", line
> 137, in run
> Registry().execute('bootstrap_initialise')
> File
> "/Users/martin/Projects/openlp/presentation/openlp/core/lib/registry.py",
> line 159, in execute
> result = function(*args, **kwargs)
> File
> "/Users/martin/Projects/openlp/presentation/openlp/core/lib/pluginmanager.py",
> line 86, in bootstrap_initialise
> self.initialise_plugins()
> File
> "/Users/martin/Projects/openlp/presentation/openlp/core/lib/pluginmanager.py",
> line 201, in initialise_plugins
> plugin.initialise()
> File
> "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/presentationplugin.py",
> line 91, in initialise
> super(PresentationPlugin, self).initialise()
> File
> "/Users/martin/Projects/openlp/presentation/openlp/core/lib/plugin.py",
> line 296, in initialise
> self.media_item.initialise()
> File
> "/Users/martin/Projects/openlp/presentation/openlp/plugins/presentations/lib/mediaitem.py",
> line 127, in initialise
> self.populate_display_types()
> File
>...

Read more...

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

I was using appscript 1.0.0. It seems like this version does not work properly with python 3.3. I upgraded to 1.0.1 and openlp is now working. I'm sorry for that. So this exception is now gone.

A few notes:
- presentation previews are not generated when a new presentation is added to openlp
- when I try to show presentation preview in openlp it complains with message:

  "The presentation file.ppt is incomplete, please reload."

What code is responsible for creating the preview from the ppt file?

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Creating preview calls from line: 597
and the code doing it is in lines: 601-638

Generating of preview should start on adding PPT to OpenLP (line: 597). But if you had file already added befor without generated preview you need to delete it and add it again.

Can you go step-by-step to the procedure "create_thumbnails" and tell me where it fails?

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

It turns out that the following line does not create any .png files:

  self.presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG)

Btw, I'm testing a .ppt file if that makes a difference. Did you test only pptx files?

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

My Powerpoint version is:

Microsoft PowerPoint for Mac 2011
Version 14.0
Latest Installed Update: 14.0.0

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

Is there any documentation or any other way what all functions/objects are provided by appscript to controll PowerPoint?

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

I have PowerPoint 14.1 (110310)
Latest installed update 14.1.0

I dont want to beleave that 14.1.0 and 14.0.0 is such big difference that "save" command doesnt work.

You can look in apple script commands here:
Open "AppleScript Editor" app
Menu: File - Open Dictionary... then select "Microsoft PowerPoint"
type save command and look into the syntax.

What i have in syntax:

save specifier: the object to save
   [in Macintosh path/Posix path]: the file in which to save the object
   [as save ast presentation/save as template/.../save as PNG/... and etc.]: the file type of the document in which to save the data

so, command on applescript, something like this:

tell presentation
   save in <path> as save as PNG
end tell

converts to call in appscript bridge as:

presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG)

What do you have in syntax?

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

On my system there is:

save v : Save an object
save specifier : the object to save
[in Macintosh path/Posix path] : the file in which to save the object
[as save as presentation/save as template/save as RTF/save as show/save as default/save as HTML/save as movie/save as package/save as PDF/save as Open XML presentation/save as Open XML presentation macro enabled/save as Open XML show/save as Open XML show macro enabled/save as Open XML template/save as Open XML template macro enabled/save as Open XML theme/save as GIF/save as JPG/save as PNG/save as BMP/save as TIF] : the file type of the document in which to save the data

It looks the same as yours.

Is it possible to update macoffice to 14.1 without additional costs?

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

I upgraded macoffice to version 14.1 and now the presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG) is working and thumbnails are generated properly.

We should mention in the manual that macoffice 14.0 is not working and upgrade to 14.1 is recommended.

I thus confirm that ppt integration on osx is working.

review: Approve
Revision history for this message
Phill (phill-ridout) wrote : Posted in a previous version of this proposal

> We should mention in the manual that macoffice 14.0 is not working and upgrade
> to 14.1 is recommended.

I've added a bug report for this: https://bugs.launchpad.net/openlp/+bug/1244242
A comment like this could easily get forgotten about, so if you notice something like this in the future please raise a bug report and use "Target to Series" to target it to the documentation series.

Is 14.x the minimum version, or is this a regression and the plugin works with earlier versions as well?

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

matysek:
Please aproove again - I just added tests and checking version of appscript

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

Phill:
We need to investigate more why PPT 14.0 is not working well. I guess we could find problem and fix it later.

Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

It still works.

review: Approve
Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal

matysek: please approve it in actual proposal version :)

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Hi Dmitriy,

One last thing: we've recently changed the way you import the "patch" and "MagicMock" objects. Please see the other tests for how to do it.

http://ci.openlp.org/view/Branch/job/Branch-02-Functional-Tests/8/console

review: Needs Fixing
Revision history for this message
matysek (mzibricky) wrote : Posted in a previous version of this proposal

When testing the latest version thumbnails are generated but when I click preview button to see the preview of the presentation in OpenLP then I get this traceback:

Traceback (most recent call last):
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 937, in emit
    msg = self.format(record)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 808, in format
    return fmt.format(record)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 554, in format
    record.exc_text = self.formatException(record.exc_info)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/logging/__init__.py", line 504, in formatException
    traceback.print_exception(ei[0], ei[1], tb, None, sio)
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/traceback.py", line 156, in print_exception
    for value, tb in values:
  File "/opt/openlp_2_2/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/traceback.py", line 122, in _iter_chain
    context = exc.__context__
AttributeError: 'NoneType' object has no attribute '__context__'
Logged from file __init__.py, line 187
Error in sys.excepthook:
RuntimeError: super-class __init__() of type ExceptionForm was never called

Original exception was:
Traceback (most recent call last):
  File "/Users/martin/Projects/openlp/bug-836574/openlp/core/lib/mediamanageritem.py", line 486, in on_preview_click
    self.preview_controller.add_service_item(service_item)
  File "/Users/martin/Projects/openlp/bug-836574/openlp/core/ui/slidecontroller.py", line 689, in add_service_item
    self._process_item(item, slide_no)
  File "/Users/martin/Projects/openlp/bug-836574/openlp/core/ui/slidecontroller.py", line 736, in _process_item
    '%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slideno])
  File "/Users/martin/Projects/openlp/bug-836574/openlp/core/lib/registry.py", line 159, in execute
    result = function(*args, **kwargs)
  File "/Users/martin/Projects/openlp/bug-836574/openlp/plugins/presentations/lib/messagelistener.py", line 319, in startup
    if self.handler == self.media_item.Automatic:

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

At least one of your import mock statements is incorrect, please see the other tests for how to correctly import mock. Also, our CI server is a Linux box, so it appears that the "appscript" module is not available. Please set the test to skip if it is not running on a Mac.

http://ci.openlp.org/view/Branch/job/Branch-02-Functional-Tests/10/console

review: Needs Fixing
Revision history for this message
Tomas Groth (tomasgroth) wrote :

Is there any chance of you fixing the tests and merge it with recent trunk updates?
This would be a very nice addition to the 2.2 release!

Revision history for this message
Tim Bentley (trb143) wrote :

Too old and out of date.
If this is still a problem please fix and resubmit.

Unmerged revisions

2143. By Dmitriy Marmyshev

tests fixes

2142. By Dmitriy Marmyshev

Trunk

2141. By Dmitriy Marmyshev

cleanups.

2140. By Dmitriy Marmyshev

Trunk

2139. By Dmitriy Marmyshev

Added check_ver for appscript module

2138. By Dmitriy Marmyshev

Tests

2137. By Dmitriy Marmyshev

thumbnail fixes

2136. By Dmitriy Marmyshev

Trunk

2135. By Dmitriy Marmyshev

fixes unicode & bzr eric5 ignore

2134. By Dmitriy Marmyshev

Trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2013-09-14 02:42:12 +0000
+++ .bzrignore 2013-10-26 22:59:24 +0000
@@ -2,6 +2,7 @@
2*.*~2*.*~
3\#*\#3\#*\#
4*.eric4project4*.eric4project
5*.eric5project
5*.ropeproject6*.ropeproject
6*.e4*7*.e4*
7.eric4project8.eric4project
89
=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py 2013-10-13 13:51:13 +0000
+++ openlp/core/lib/pluginmanager.py 2013-10-26 22:59:24 +0000
@@ -94,11 +94,6 @@
94 present_plugin_dir = os.path.join(self.base_path, 'presentations')94 present_plugin_dir = os.path.join(self.base_path, 'presentations')
95 log.debug('finding plugins in %s at depth %d', str(self.base_path), start_depth)95 log.debug('finding plugins in %s at depth %d', str(self.base_path), start_depth)
96 for root, dirs, files in os.walk(self.base_path):96 for root, dirs, files in os.walk(self.base_path):
97 if sys.platform == 'darwin' and root.startswith(present_plugin_dir):
98 # TODO Presentation plugin is not yet working on Mac OS X.
99 # For now just ignore it. The following code will ignore files from the presentation plugin directory
100 # and thereby never import the plugin.
101 continue
102 for name in files:97 for name in files:
103 if name.endswith('.py') and not name.startswith('__'):98 if name.endswith('.py') and not name.startswith('__'):
104 path = os.path.abspath(os.path.join(root, name))99 path = os.path.abspath(os.path.join(root, name))
105100
=== modified file 'openlp/core/ui/firsttimeform.py'
--- openlp/core/ui/firsttimeform.py 2013-10-13 21:07:28 +0000
+++ openlp/core/ui/firsttimeform.py 2013-10-26 22:59:24 +0000
@@ -414,10 +414,7 @@
414 self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...'))414 self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...'))
415 self._set_plugin_status(self.songs_check_box, 'songs/status')415 self._set_plugin_status(self.songs_check_box, 'songs/status')
416 self._set_plugin_status(self.bible_check_box, 'bibles/status')416 self._set_plugin_status(self.bible_check_box, 'bibles/status')
417 # TODO Presentation plugin is not yet working on Mac OS X.417 self._set_plugin_status(self.presentation_check_box, 'presentations/status')
418 # For now just ignore it.
419 if sys.platform != 'darwin':
420 self._set_plugin_status(self.presentation_check_box, 'presentations/status')
421 self._set_plugin_status(self.image_check_box, 'images/status')418 self._set_plugin_status(self.image_check_box, 'images/status')
422 self._set_plugin_status(self.media_check_box, 'media/status')419 self._set_plugin_status(self.media_check_box, 'media/status')
423 self._set_plugin_status(self.remote_check_box, 'remotes/status')420 self._set_plugin_status(self.remote_check_box, 'remotes/status')
424421
=== modified file 'openlp/core/ui/firsttimewizard.py'
--- openlp/core/ui/firsttimewizard.py 2013-10-13 21:07:28 +0000
+++ openlp/core/ui/firsttimewizard.py 2013-10-26 22:59:24 +0000
@@ -93,13 +93,10 @@
93 self.image_check_box.setChecked(True)93 self.image_check_box.setChecked(True)
94 self.image_check_box.setObjectName('image_check_box')94 self.image_check_box.setObjectName('image_check_box')
95 self.plugin_layout.addWidget(self.image_check_box)95 self.plugin_layout.addWidget(self.image_check_box)
96 # TODO Presentation plugin is not yet working on Mac OS X.96 self.presentation_check_box = QtGui.QCheckBox(self.plugin_page)
97 # For now just ignore it.97 self.presentation_check_box.setChecked(True)
98 if sys.platform != 'darwin':98 self.presentation_check_box.setObjectName('presentation_check_box')
99 self.presentation_check_box = QtGui.QCheckBox(self.plugin_page)99 self.plugin_layout.addWidget(self.presentation_check_box)
100 self.presentation_check_box.setChecked(True)
101 self.presentation_check_box.setObjectName('presentation_check_box')
102 self.plugin_layout.addWidget(self.presentation_check_box)
103 self.media_check_box = QtGui.QCheckBox(self.plugin_page)100 self.media_check_box = QtGui.QCheckBox(self.plugin_page)
104 self.media_check_box.setChecked(True)101 self.media_check_box.setChecked(True)
105 self.media_check_box.setObjectName('media_check_box')102 self.media_check_box.setObjectName('media_check_box')
@@ -219,10 +216,7 @@
219 self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides'))216 self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides'))
220 self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))217 self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))
221 self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Images'))218 self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Images'))
222 # TODO Presentation plugin is not yet working on Mac OS X.219 self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations'))
223 # For now just ignore it.
224 if sys.platform != 'darwin':
225 self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations'))
226 self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)'))220 self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)'))
227 self.remote_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access'))221 self.remote_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access'))
228 self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Monitor Song Usage'))222 self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Monitor Song Usage'))
229223
=== added file 'openlp/plugins/presentations/lib/keynotemaccontroller.py'
--- openlp/plugins/presentations/lib/keynotemaccontroller.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/presentations/lib/keynotemaccontroller.py 2013-10-26 22:59:24 +0000
@@ -0,0 +1,360 @@
1# -*- coding: utf-8 -*-
2# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
3
4###############################################################################
5# OpenLP - Open Source Lyrics Projection #
6# --------------------------------------------------------------------------- #
7# Copyright (c) 2008-2012 Raoul Snyman #
8# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
9# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
10# Meinert Jordan, Armin Köhler, Eric Ludin, Edwin Lunando, Brian T. Meyer, #
11# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
12# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
13# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
14# Frode Woldsund, Martin Zibricky #
15# --------------------------------------------------------------------------- #
16# This program is free software; you can redistribute it and/or modify it #
17# under the terms of the GNU General Public License as published by the Free #
18# Software Foundation; version 2 of the License. #
19# #
20# This program is distributed in the hope that it will be useful, but WITHOUT #
21# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
22# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
23# more details. #
24# #
25# You should have received a copy of the GNU General Public License along #
26# with this program; if not, write to the Free Software Foundation, Inc., 59 #
27# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
28###############################################################################
29
30import os
31import logging
32import appscript
33
34from openlp.core.common import Settings
35from openlp.core.lib import ScreenList
36from .presentationcontroller import PresentationController, PresentationDocument
37
38
39log = logging.getLogger(__name__)
40
41
42class KeynoteController(PresentationController):
43 """
44 Class to control interactions with KeyNote Presentations
45 It creates the runtime Environment , Loads the and Closes the Presentation
46 As well as triggering the correct activities based on the users input
47 """
48 log.info('KeynoteController loaded')
49
50 def __init__(self, plugin):
51 """
52 Initialise the class
53 """
54 log.debug('Initialising')
55 super(KeynoteController, self).__init__(plugin, 'Keynote', KeynoteDocument)
56 self.supports = ['key']
57 self.process = None
58
59 def check_available(self):
60 """
61 KeyNote is able to run on this machine
62 """
63 log.debug('check_available')
64 try:
65 self.process = appscript.app('Keynote')
66 except appscript.ApplicationNotFoundError:
67 return False
68 self.kill()
69 return True
70
71 def start_process(self):
72 """
73 Loads KeyNote process
74 """
75 log.debug('start_process')
76 if not self.process or not self.process.isrunning():
77 self.process = appscript.app('Keynote')
78 self.process.relaunchmode = 'limited' #'always'
79 self.process.launch()
80 self.apply_app_settings()
81
82 def kill(self):
83 """
84 Called at system exit to clean up any running presentations
85 """
86 log.debug('Kill Keynote')
87 while self.docs and self.process.isrunning():
88 self.docs[0].close_presentation()
89 if self.process is None or not self.process.isrunning():
90 return
91 try:
92 total = self.process.slideshows()
93 if self.process and total != appscript.k.missing_value and len(total) > 0:
94 return
95 self.process.quit(saving = appscript.k.ask)
96 except appscript.CantLaunchApplicationError:
97 log.debug('Kill Keynote failed')
98 self.process = None
99
100 def apply_app_settings(self):
101 """
102 Apply settings for Keynote
103 PresentationModeEnableFeedbackDisplay = True if in settings of OpenLP show presenter view = True
104 PresentationModeUseSecondary = 1 if OpenLP monitor for output = Screen 2
105 """
106 openlp_settings = Settings('openlp.org','OpenLP')
107 keynote_settings = Settings('apple', 'iWork.Keynote')
108 use_secondary = int(keynote_settings.value('PresentationModeUseSecondary'))
109 monitor = openlp_settings.value( 'core/monitor')
110 override_position = openlp_settings.value( 'core/override position')
111 if not override_position and use_secondary != monitor:
112 keynote_settings.setValue('PresentationModeUseSecondary', monitor)
113 elif override_position and use_secondary != 0:
114 keynote_settings.setValue('PresentationModeUseSecondary', '0')
115 show_presenter_view = openlp_settings.value(self.plugin.settings_section + '/show presenter view')
116 keynote_feedback_display = keynote_settings.value('PresentationModeEnableFeedbackDisplay')
117 if show_presenter_view != keynote_feedback_display:
118 keynote_settings.setValue('PresentationModeEnableFeedbackDisplay', show_presenter_view)
119 play_well_with_others = keynote_settings.value('PresentationModePlayWellWithOthers')
120 if not play_well_with_others:
121 keynote_settings.setValue('PresentationModePlayWellWithOthers', True)
122
123
124class KeynoteDocument(PresentationDocument):
125 """
126 Class which holds information and controls a single presentation
127 """
128
129 def __init__(self, controller, presentation):
130 """
131 Constructor, store information about the file and initialise
132 """
133 log.debug('Init Presentation Keynote')
134 super(KeynoteDocument, self).__init__(controller, presentation)
135 self.presentation = None
136
137 def load_presentation(self):
138 """
139 Called when a presentation is added to the SlideController.
140 Opens the Keynote file using the process created earlier.
141 """
142 log.debug('load_presentation')
143 if not self.controller.process or not self.controller.process.isrunning():
144 self.controller.start_process()
145 try:
146 self.controller.process.open(self.filepath)
147 except appscript.CommandError:
148 log.debug('Keynote open failed')
149 return False
150 slideshows = self.controller.process.slideshows()
151 for slideshow in slideshows:
152 path = slideshow.path()
153 if self.filepath == path:
154 self.presentation = slideshow
155 self.create_thumbnails()
156 return True
157 self.presentation = None
158 return False
159
160 def create_thumbnails(self):
161 """
162 Create the thumbnail images for the current presentation.
163 """
164 log.debug('create_thumbnails')
165 if self.check_thumbnails():
166 return
167 thumbnail_folder = self.get_thumbnail_folder()
168 if not os.path.exists(thumbnail_folder):
169 os.makedirs(thumbnail_folder)
170 try:
171 self.controller.process.open(self.filepath)
172 except appscript.CommandError:
173 log.debug('KeyNote open failed')
174 return
175 temp_dir = self.controller.thumbnail_folder
176 keystroke = os.path.join(temp_dir, 'temp' + self.controller.thumbnail_prefix)
177 self.controller.process.activate()
178 appscript.app('System Events').processes['Keynote'].menu_bars[1].menu_bar_items[3].menus.menu_items[11].click()
179 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].tool_bars.buttons[4].click()
180 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].radio_groups[1].radio_buttons[1].click()
181 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].pop_up_buttons[1].click()
182 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].pop_up_buttons[1]\
183 .menus.menu_items[2].click()
184 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].buttons[2].click()
185 appscript.app('System Events').processes['Keynote'].keystroke(keystroke)
186 appscript.app('System Events').processes['Keynote'].key_code(36)
187 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].buttons[1].click()
188 self.controller.plugin._main_window.activateWindow()
189 slide_no = 0
190 for filename in os.listdir(temp_dir):
191 full_filename = os.path.join(temp_dir, filename)
192 if not os.path.isfile(full_filename) or not filename.endswith('.png') or filename == 'icon.png':
193 continue
194 slide_no = slide_no + 1
195 if not filename.startswith(self.controller.thumbnail_prefix):
196 path = os.path.join(thumbnail_folder,
197 self.controller.thumbnail_prefix + str(slide_no) + '.png')
198 try:
199 os.rename(full_filename, path)
200 except:
201 open(path,'w').write(open(full_filename,'r').read())
202 os.unlink(full_filename)
203
204 def close_presentation(self):
205 """
206 Close presentation and clean up objects. This is triggered by a new
207 object being added to SlideController or OpenLP being shut down.
208 """
209 log.debug('close_presentation')
210 if self.presentation:
211 try:
212 self.presentation.close()
213 except appscript.CommandError:
214 log.debug('Could not close the presentation')
215 self.presentation = None
216 self.controller.remove_doc(self)
217
218 def is_loaded(self):
219 """
220 Returns ``True`` if a presentation is loaded.
221 """
222 log.debug('is_loaded')
223 try:
224 if not self.controller.process.isrunning():
225 return False
226 windows = self.controller.process.windows()
227 if len(windows) == 0:
228 return False
229 slideshows = self.controller.process.slideshows()
230 if len(slideshows) == 0:
231 return False
232 except:
233 return False
234 for slideshow in slideshows:
235 path = slideshow.path()
236 if self.filepath == path:
237 return True
238 return False
239
240 def is_active(self):
241 """
242 Returns ``True`` if a presentation is currently active.
243 """
244 log.debug('is_active')
245 if not self.is_loaded():
246 return False
247 try:
248 if not self.presentation.playing():
249 return False
250 except appscript.CommandError:
251 return False
252 return True
253
254 def unblank_screen(self):
255 """
256 Unblanks (restores) the presentation.
257 """
258 log.debug('unblank_screen')
259 if self.is_blank():
260 self.presentation.start_presentation()
261
262 def blank_screen(self):
263 """
264 Blanks the screen.
265 """
266 log.debug('blank_screen')
267 self.presentation.stop_slideshow()
268
269 def is_blank(self):
270 """
271 Returns ``True`` if screen is blank.
272 """
273 log.debug('is_blank')
274 if self.is_active():
275 return not self.presentation.playing()
276 else:
277 return False
278
279 def stop_presentation(self):
280 """
281 Stops the current presentation and hides the output.
282 """
283 log.debug('stop_presentation')
284 self.presentation.stop_slideshow()
285
286
287 def start_presentation(self):
288 """
289 Starts a presentation from the beginning.
290 """
291 log.debug('start_presentation')
292 if not self.is_active():
293 self.controller.apply_app_settings()
294 try:
295 self.presentation.start()
296 except appscript.CommandError:
297 return
298 rect = ScreenList().current['size']
299 top = rect.y()
300 height = rect.height()
301 left_position = rect.x()
302 width = rect.width()
303 self.controller.process.windows[1].bounds.set([left_position, top, left_position + width, top + height])
304
305 def get_slide_number(self):
306 """
307 Returns the current slide number.
308 """
309 log.debug('get_slide_number')
310 return self.presentation.current_slide().slide_number()
311
312 def get_slide_count(self):
313 """
314 Returns total number of slides.
315 """
316 log.debug('get_slide_count')
317 slides = self.presentation.slides()
318 return len(slides)
319
320 def goto_slide(self, slideno):
321 """
322 Moves to a specific slide in the presentation.
323 """
324 log.debug('goto_slide')
325 slide = self.presentation.slides()[slideno-1]
326 self.presentation.show(slide)
327
328 def next_step(self):
329 """
330 Triggers the next effect of slide on the running presentation.
331 """
332 log.debug('next_step')
333 self.presentation.show_next()
334 if self.get_slide_number() > self.get_slide_count():
335 self.previous_step()
336
337 def previous_step(self):
338 """
339 Triggers the previous slide on the running presentation.
340 """
341 log.debug('previous_step')
342 self.presentation.show_previous()
343
344 def get_slide_text(self, slide_no):
345 """
346 Returns the text on the slide.
347
348 ``slide_no``
349 The slide the text is required for, starting at 1.
350 """
351 return self.presentation.slides[slide_no].body
352
353 def get_slide_notes(self, slide_no):
354 """
355 Returns the text on the slide.
356
357 ``slide_no``
358 The slide the notes are required for, starting at 1.
359 """
360 return self.presentation.slides[slide_no].notes
0361
=== added file 'openlp/plugins/presentations/lib/powerpointmaccontroller.py'
--- openlp/plugins/presentations/lib/powerpointmaccontroller.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/presentations/lib/powerpointmaccontroller.py 2013-10-26 22:59:24 +0000
@@ -0,0 +1,397 @@
1# -*- coding: utf-8 -*-
2# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
3
4###############################################################################
5# OpenLP - Open Source Lyrics Projection #
6# --------------------------------------------------------------------------- #
7# Copyright (c) 2008-2012 Raoul Snyman #
8# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
9# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
10# Meinert Jordan, Armin Köhler, Eric Ludin, Edwin Lunando, Brian T. Meyer, #
11# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
12# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
13# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
14# Frode Woldsund, Martin Zibricky #
15# --------------------------------------------------------------------------- #
16# This program is free software; you can redistribute it and/or modify it #
17# under the terms of the GNU General Public License as published by the Free #
18# Software Foundation; version 2 of the License. #
19# #
20# This program is distributed in the hope that it will be useful, but WITHOUT #
21# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
22# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
23# more details. #
24# #
25# You should have received a copy of the GNU General Public License along #
26# with this program; if not, write to the Free Software Foundation, Inc., 59 #
27# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
28###############################################################################
29
30import os
31import logging
32import shutil
33
34import appscript
35
36from openlp.core.common import Settings
37from openlp.core.lib import ScreenList
38from .presentationcontroller import PresentationController, PresentationDocument
39
40
41log = logging.getLogger(__name__)
42
43
44class PowerpointController(PresentationController):
45 """
46 Class to control interactions with PowerPoint Presentations
47 It creates the runtime Environment , Loads the and Closes the Presentation
48 As well as triggering the correct activities based on the users input
49 """
50 log.info(u'PowerpointController loaded')
51
52 def __init__(self, plugin):
53 """
54 Initialise the class
55 """
56 log.debug('Initialising')
57 super(PowerpointController, self).__init__(plugin, 'Powerpoint', PowerpointDocument)
58 self.supports = ['ppt', 'pps', 'pptx', 'ppsx']
59 self.process = None
60
61 def check_available(self):
62 """
63 PowerPoint is able to run on this machine
64 """
65 log.debug('check_available')
66 try:
67 self.process = appscript.app(id='com.microsoft.powerpoint')
68 except appscript.ApplicationNotFoundError:
69 return False
70 self.kill()
71 return True
72
73 def start_process(self):
74 """
75 Loads PowerPoint process
76 """
77 log.debug('start_process')
78 if not self.process or not self.process.isrunning():
79 self.process = appscript.app(id='com.microsoft.powerpoint')
80 self.process.relaunchmode = 'limited' #'always'
81 self.process.launch()
82 self.apply_app_settings()
83
84 def kill(self):
85 """
86 Called at system exit to clean up any running presentations
87 """
88 log.debug('Kill Powerpoint')
89 while self.docs and self.process.isrunning():
90 self.docs[0].close_presentation()
91 if self.process is None or not self.process.isrunning():
92 return
93 try:
94 total = self.process.presentations()
95 if self.process and total != appscript.k.missing_value and len(total) > 0:
96 return
97 self.process.quit(saving = appscript.k.ask)
98 except appscript.CantLaunchApplicationError:
99 log.debug('Kill Keynote failed')
100 self.process = None
101
102 def apply_app_settings(self):
103 """
104 Apply settings for PowerPoint
105 14\Options\Options\Save graphics screen heigth = 240
106 14\Options\Options\Save graphics screen width = 320
107 14\Options\Options\Save only current slide graphics = 0
108
109 """
110 #TODO: add settings for different versions of MS PPT
111 pass
112
113
114class PowerpointDocument(PresentationDocument):
115 """
116 Class which holds information and controls a single presentation
117 """
118
119 def __init__(self, controller, presentation):
120 """
121 Constructor, store information about the file and initialise
122 """
123 log.debug('Init Presentation Powerpoint')
124 super(PowerpointDocument, self).__init__(controller, presentation)
125 self.presentation = None
126
127 def load_presentation(self):
128 """
129 Called when a presentation is added to the SlideController.
130 Opens the PowerPoint file using the process created earlier.
131 """
132 log.debug('load_presentation')
133 if not self.controller.process or not self.controller.process.isrunning():
134 self.controller.start_process()
135 try:
136 self.controller.process.open(self.filepath)
137 except appscript.CommandError:
138 log.debug('PPT open failed')
139 return False
140 presentations = self.controller.process.presentations()
141 for presentation in presentations:
142 full_name = presentation.full_name()
143 full_name = full_name.replace('Macintosh HD', '')
144 full_name = full_name.replace(':', '/')
145 if self.filepath == full_name:
146 self.presentation = presentation
147 self.create_thumbnails()
148 return True
149 return False
150
151 def create_thumbnails(self):
152 """
153 Create the thumbnail images for the current presentation.
154 """
155 log.debug('create_thumbnails')
156 if self.check_thumbnails():
157 return
158 thumbnail_folder = self.get_thumbnail_folder()
159 self.presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG)
160 slide_no = 0
161 self.move_thumbnails(thumbnail_folder, slide_no, thumbnail_folder)
162
163 def move_thumbnails(self, thumbnail_folder, slide_no, temp_dir):
164 """
165 Move the thumbnail images from subdirectories to right path.
166 """
167 if not os.path.isdir(temp_dir):
168 return
169 for filename in os.listdir(temp_dir):
170 full_filename = os.path.join(temp_dir, filename)
171 if os.path.isdir(full_filename):
172 self.move_thumbnails(thumbnail_folder, slide_no, full_filename)
173 elif os.path.isfile(full_filename) and filename.endswith('.png') and not filename == 'icon.png':
174 slide_no = slide_no + 1
175 new_name = os.path.join(thumbnail_folder, self.controller.thumbnail_prefix + str(slide_no) + '.png')
176 if full_filename == new_name \
177 or full_filename.startswith(os.path.join(thumbnail_folder, self.controller.thumbnail_prefix)):
178 continue
179 try:
180 os.rename(full_filename, new_name)
181 except:
182 open(new_name,'w').write(open(full_filename,'r').read())
183 os.unlink(full_filename)
184 if temp_dir != thumbnail_folder:
185 try:
186 shutil.rmtree(temp_dir)
187 except:
188 pass
189
190 def close_presentation(self):
191 """
192 Close presentation and clean up objects. This is triggered by a new
193 object being added to SlideController or OpenLP being shut down.
194 """
195 log.debug('close_presentation')
196 if self.presentation:
197 try:
198 self.presentation.close()
199 except appscript.CommandError:
200 log.debug('Could not close the presentation')
201 self.presentation = None
202 self.controller.remove_doc(self)
203
204 def is_loaded(self):
205 """
206 Returns ``True`` if a presentation is loaded.
207 """
208 log.debug('is_loaded')
209 try:
210 if not self.controller.process.isrunning():
211 return False
212 if len(self.controller.process.document_windows()) == 0:
213 return False
214 presentations = self.controller.process.presentations()
215 if len(presentations) == 0:
216 return False
217 except:
218 return False
219 for presentation in presentations:
220 full_name = presentation.full_name()
221 full_name = full_name.replace('Macintosh HD', '')
222 full_name = full_name.replace(':', '/')
223 if self.filepath == full_name:
224 return True
225 return False
226
227 def is_active(self):
228 """
229 Returns ``True`` if a presentation is currently active.
230 """
231 log.debug('is_active')
232 if not self.is_loaded():
233 return False
234 try:
235 slide_show_window = self.presentation.slide_show_window
236 if slide_show_window is None:
237 return False
238 slide_state = self.presentation.slide_show_window.slideshow_view.slide_state()
239 if slide_state is None or slide_state == appscript.k.missing_value:
240 return False
241 except:
242 return False
243 return True
244
245 def unblank_screen(self):
246 """
247 Unblanks (restores) the presentation.
248 """
249 log.debug('unblank_screen')
250 if self.is_blank():
251 self.presentation.slide_show_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_running)
252 self.presentation.slide_show_window.slideshow_view.go_to_next_slide()
253 self.presentation.slide_show_window.slideshow_view.go_to_previous_slide()
254
255 def blank_screen(self):
256 """
257 Blanks the screen.
258 """
259 log.debug('blank_screen')
260 self.presentation.slide_show_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_black_screen)
261
262 def is_blank(self):
263 """
264 Returns ``True`` if screen is blank.
265 """
266 log.debug('is_blank')
267 if self.is_active() and self.presentation.slide_show_window.slideshow_view\
268 .slide_state() is appscript.k.slide_show_state_black_screen:
269 return True
270 else:
271 return False
272
273 def stop_presentation(self):
274 """
275 Stops the current presentation and hides the output.
276 """
277 log.debug('stop_presentation')
278 self.presentation.slide_show_window.slideshow_view.exit_slide_show()
279
280
281 def start_presentation(self):
282 """
283 Starts a presentation from the beginning.
284 """
285 log.debug('start_presentation')
286 rect = ScreenList().current['size']
287 ppt_settings = self.presentation.slide_show_settings
288 openlp_settings = Settings("openlp.org","OpenLP")
289 show_presenter_view = openlp_settings.value(self.controller.plugin.settings_section + '/show presenter view')
290 override_position = openlp_settings.value( 'general/override position')
291 if show_presenter_view:
292 ppt_settings.show_type.set(appscript.k.slide_show_type_presenter)
293 elif override_position:
294 ppt_settings.show_type.set(appscript.k.slide_show_type_window)
295 else:
296 ppt_settings.show_type.set(appscript.k.slide_show_type_kiosk)
297 #ppt_settings.show_type.set(appscript.k.slide_show_type_speaker)
298 ppt_window = ppt_settings.run_slide_show()
299 #TODO: set slideshow state = running
300 #if ppt_window.slideshow_view.slide_state() != appscript.k.slide_show_state_running:
301 # ppt_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_running)
302 if not ppt_window or show_presenter_view:
303 return
304 if override_position:
305 top = float(rect.y())
306 height = float(rect.height())
307 left_position = float(rect.x())
308 width = float(rect.width())
309 ppt_window.top.set(top)
310 ppt_window.height.set(height)
311 ppt_window.left_position.set(left_position)
312 ppt_window.width.set(width)
313 else:
314 #TODO: set output monitor for fullscreen mode
315 pass
316
317 def get_slide_number(self):
318 """
319 Returns the current slide number.
320 """
321 log.debug('get_slide_number')
322 return self.presentation.slide_show_window.slideshow_view.current_show_position()
323
324 def get_slide_count(self):
325 """
326 Returns total number of slides.
327 """
328 log.debug('get_slide_count')
329 return len(self.presentation.slides())
330
331 def goto_slide(self, slideno):
332 """
333 Moves to a specific slide in the presentation.
334 """
335 log.debug('goto_slide')
336 #FIXME: this works. but needs to fix this code
337 while self.get_slide_number() != slideno:
338 if self.get_slide_number() < slideno:
339 self.presentation.slide_show_window.slideshow_view.go_to_next_slide()
340 else:
341 self.presentation.slide_show_window.slideshow_view.go_to_previous_slide()
342 self.controller.process.activate()
343
344 def next_step(self):
345 """
346 Triggers the next effect of slide on the running presentation.
347 """
348 log.debug('next_step')
349 #TODO: check if slideshow stoped then restart it from current position
350 if self.is_active():
351 self.presentation.slide_show_window.slideshow_view.go_to_next_slide()
352 self.controller.process.activate()
353 if self.get_slide_number() > self.get_slide_count():
354 self.previous_step()
355
356 def previous_step(self):
357 """
358 Triggers the previous slide on the running presentation.
359 """
360 log.debug('previous_step')
361 #TODO: check if slideshow stoped then restart it from current position
362 if self.is_active():
363 self.presentation.slide_show_window.slideshow_view.go_to_previous_slide()
364 self.controller.process.activate()
365
366 def get_slide_text(self, slide_no):
367 """
368 Returns the text on the slide.
369
370 ``slide_no``
371 The slide the text is required for, starting at 1.
372 """
373 return _get_text_from_shapes(self.presentation.slides[slide_no-1].shapes)
374
375 def get_slide_notes(self, slide_no):
376 """
377 Returns the text on the slide.
378
379 ``slide_no``
380 The slide the notes are required for, starting at 1.
381 """
382 return _get_text_from_shapes(
383 self.presentation.slides[slide_no].notes_page.shapes())
384
385def _get_text_from_shapes(shapes):
386 """
387 Returns any text extracted from the shapes on a presentation slide.
388
389 ``shapes``
390 A set of shapes to search for text.
391 """
392 text = ''
393 for idx in range(len(shapes)):
394 shape = shapes[idx + 1]
395 if shape.has_text_frame():
396 text += shape.text_frame.text_range.content() + '\n'
397 return text
0398
=== modified file 'openlp/plugins/presentations/lib/presentationtab.py'
--- openlp/plugins/presentations/lib/presentationtab.py 2013-10-13 20:36:42 +0000
+++ openlp/plugins/presentations/lib/presentationtab.py 2013-10-26 22:59:24 +0000
@@ -27,6 +27,8 @@
27# Temple Place, Suite 330, Boston, MA 02111-1307 USA #27# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
28###############################################################################28###############################################################################
2929
30import sys
31
30from PyQt4 import QtGui32from PyQt4 import QtGui
3133
32from openlp.core.common import Settings, UiStrings, translate34from openlp.core.common import Settings, UiStrings, translate
@@ -71,6 +73,11 @@
71 self.override_app_check_box = QtGui.QCheckBox(self.advanced_group_box)73 self.override_app_check_box = QtGui.QCheckBox(self.advanced_group_box)
72 self.override_app_check_box.setObjectName('override_app_check_box')74 self.override_app_check_box.setObjectName('override_app_check_box')
73 self.advanced_layout.addWidget(self.override_app_check_box)75 self.advanced_layout.addWidget(self.override_app_check_box)
76 self.show_presenter_view_check_box = QtGui.QCheckBox(self.advanced_group_box)
77 self.show_presenter_view_check_box.setObjectName(u'show_presenter_view_check_box')
78 self.advanced_layout.addWidget(self.show_presenter_view_check_box)
79 if not sys.platform.startswith('darwin'):
80 self.show_presenter_view_check_box.setVisible(False)
74 self.left_layout.addWidget(self.advanced_group_box)81 self.left_layout.addWidget(self.advanced_group_box)
75 self.left_layout.addStretch()82 self.left_layout.addStretch()
76 self.right_layout.addStretch()83 self.right_layout.addStretch()
@@ -87,6 +94,8 @@
87 self.advanced_group_box.setTitle(UiStrings().Advanced)94 self.advanced_group_box.setTitle(UiStrings().Advanced)
88 self.override_app_check_box.setText(95 self.override_app_check_box.setText(
89 translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden'))96 translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden'))
97 self.show_presenter_view_check_box.setText(translate('PresentationPlugin.PresentationTab',
98 'Show Presenter View'))
9099
91 def set_controller_text(self, checkbox, controller):100 def set_controller_text(self, checkbox, controller):
92 if checkbox.isEnabled():101 if checkbox.isEnabled():
@@ -103,6 +112,7 @@
103 checkbox = self.presenter_check_boxes[controller.name]112 checkbox = self.presenter_check_boxes[controller.name]
104 checkbox.setChecked(Settings().value(self.settings_section + '/' + controller.name))113 checkbox.setChecked(Settings().value(self.settings_section + '/' + controller.name))
105 self.override_app_check_box.setChecked(Settings().value(self.settings_section + '/override app'))114 self.override_app_check_box.setChecked(Settings().value(self.settings_section + '/override app'))
115 self.show_presenter_view_check_box.setChecked(Settings().value(self.settings_section + '/show presenter view'))
106116
107 def save(self):117 def save(self):
108 """118 """
@@ -128,6 +138,10 @@
128 if Settings().value(setting_key) != self.override_app_check_box.checkState():138 if Settings().value(setting_key) != self.override_app_check_box.checkState():
129 Settings().setValue(setting_key, self.override_app_check_box.checkState())139 Settings().setValue(setting_key, self.override_app_check_box.checkState())
130 changed = True140 changed = True
141 setting_key = self.settings_section + '/show presenter view'
142 if Settings().value(setting_key) != self.show_presenter_view_check_box.checkState():
143 Settings().setValue(setting_key, self.show_presenter_view_check_box.isChecked())
144 changed = True
131 if changed:145 if changed:
132 self.settings_form.register_post_process('mediaitem_suffix_reset')146 self.settings_form.register_post_process('mediaitem_suffix_reset')
133 self.settings_form.register_post_process('mediaitem_presentation_rebuild')147 self.settings_form.register_post_process('mediaitem_presentation_rebuild')
134148
=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py 2013-10-13 21:07:28 +0000
+++ openlp/plugins/presentations/presentationplugin.py 2013-10-26 22:59:24 +0000
@@ -31,6 +31,7 @@
31formats.31formats.
32"""32"""
33import os33import os
34import sys
34import logging35import logging
3536
36from PyQt4 import QtCore37from PyQt4 import QtCore
@@ -48,6 +49,11 @@
48 'presentations/Impress': QtCore.Qt.Checked,49 'presentations/Impress': QtCore.Qt.Checked,
49 'presentations/Powerpoint': QtCore.Qt.Checked,50 'presentations/Powerpoint': QtCore.Qt.Checked,
50 'presentations/Powerpoint Viewer': QtCore.Qt.Checked,51 'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
52 'presentations/Keynote': QtCore.Qt.Checked,
53 'presentations/show presenter view': QtCore.Qt.Checked,
54 'PresentationModeUseSecondary': '',
55 'PresentationModeEnableFeedbackDisplay': False,
56 'PresentationModePlayWellWithOthers': False,
51 'presentations/presentations files': []57 'presentations/presentations files': []
52}58}
5359
@@ -125,6 +131,12 @@
125 controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'presentations', 'lib')131 controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'presentations', 'lib')
126 for filename in os.listdir(controller_dir):132 for filename in os.listdir(controller_dir):
127 if filename.endswith('controller.py') and not filename == 'presentationcontroller.py':133 if filename.endswith('controller.py') and not filename == 'presentationcontroller.py':
134 if not sys.platform.startswith('darwin') and filename == 'powerpointmaccontroller.py':
135 continue
136 if not sys.platform.startswith('darwin') and filename == 'keynotemaccontroller.py':
137 continue
138 if not sys.platform.startswith('win') and filename == 'powerpointcontroller.py':
139 continue
128 path = os.path.join(controller_dir, filename)140 path = os.path.join(controller_dir, filename)
129 if os.path.isfile(path):141 if os.path.isfile(path):
130 module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0]142 module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0]
131143
=== modified file 'scripts/check_dependencies.py'
--- scripts/check_dependencies.py 2013-10-03 19:56:12 +0000
+++ scripts/check_dependencies.py 2013-10-26 22:59:24 +0000
@@ -47,6 +47,7 @@
47 nose = None47 nose = None
4848
49IS_WIN = sys.platform.startswith('win')49IS_WIN = sys.platform.startswith('win')
50IS_OSX = sys.platform.startswith('darwin')
5051
5152
52VERS = {53VERS = {
@@ -57,6 +58,8 @@
57 # pyenchant 1.6 required on Windows58 # pyenchant 1.6 required on Windows
58 'enchant': '1.6' if IS_WIN else '1.3'59 'enchant': '1.6' if IS_WIN else '1.3'
59}60}
61if IS_OSX:
62 VERS.update({'appscript': '1.0.0'})
6063
61# pywin3264# pywin32
62WIN32_MODULES = [65WIN32_MODULES = [
@@ -67,6 +70,11 @@
67 'icu',70 'icu',
68]71]
6972
73# OSX
74OSX_MODULES = [
75 'appscript',
76 'mactypes',
77]
70MODULES = [78MODULES = [
71 'PyQt4',79 'PyQt4',
72 'PyQt4.QtCore',80 'PyQt4.QtCore',
@@ -177,6 +185,12 @@
177 check_vers(enchant.__version__, VERS['enchant'], 'enchant')185 check_vers(enchant.__version__, VERS['enchant'], 'enchant')
178 except ImportError:186 except ImportError:
179 print_vers_fail(VERS['enchant'], 'enchant')187 print_vers_fail(VERS['enchant'], 'enchant')
188 if IS_OSX:
189 try:
190 import appscript
191 check_vers(appscript.__version__, VERS['appscript'], 'appscript')
192 except ImportError:
193 print_vers_fail(VERS['appscript'], 'appscript')
180194
181195
182def print_enchant_backends_and_languages():196def print_enchant_backends_and_languages():
@@ -228,6 +242,10 @@
228 print('Checking for Windows specific modules...')242 print('Checking for Windows specific modules...')
229 for m in WIN32_MODULES:243 for m in WIN32_MODULES:
230 check_module(m)244 check_module(m)
245 if IS_OSX:
246 print('Checking for OS X specific modules...')
247 for m in OSX_MODULES:
248 check_module(m)
231 verify_versions()249 verify_versions()
232 print_qt_image_formats()250 print_qt_image_formats()
233 print_enchant_backends_and_languages()251 print_enchant_backends_and_languages()
234252
=== added file 'tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py'
--- tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py 2013-10-26 22:59:24 +0000
@@ -0,0 +1,93 @@
1"""
2This module contains tests for the KeynoteController class of the Presentations plugin.
3"""
4
5from unittest import TestCase
6
7from tests.functional import MagicMock
8import os
9from openlp.plugins.presentations.lib.keynotemaccontroller import KeynoteController, KeynoteDocument
10
11RESOURCES_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
12
13# TODO: write tests for classes
14# - KeynoteController
15# - KeynoteDocument
16
17class TestKeynoteController(TestCase):
18 """
19 Test the KeynoteController class
20 """
21 def setUp(self):
22 """
23 Set up the KeynoteController
24 """
25 presentation_controller = MagicMock()
26 presentation_controller.settings_section = 'presentations'
27 self.keynote_controller = KeynoteController(presentation_controller)
28 self.file_name = os.path.join(RESOURCES_PATH,'test.key')
29 self.doc = KeynoteDocument(self.keynote_controller,self.file_name)
30 self.doc.presentation_deleted()
31
32 def kill_test(self):
33 """
34 Test running the kill() method with an KeynoteController
35 """
36 # GIVEN: A KeynoteController instance and a list of documents
37 presentation_controller = MagicMock()
38 presentation_controller.settings_section = 'presentations'
39 keynote_controller = KeynoteController(presentation_controller)
40 key_document = MagicMock()
41 keynote_controller.docs.append(key_document)
42 # WHEN: we run kill()
43 keynote_controller.kill()
44 # THEN: all docs should be deleted from controller
45 assert keynote_controller.docs.count() == 0, 'The keynote_controller should close all documents.'
46 assert keynote_controller.process in None, 'The keynote_controller should shout down KeyNote application.'
47
48 def verify_installation_test(self):
49 """
50 Test the installation of KeyNote
51 """
52 # GIVEN: A boolean value set to true
53 # WHEN: We "convert" it to a bool
54 is_installed = self.keynote_controller.check_available()
55 # THEN: We should get back a True bool
56 assert is_installed is True, u'The result of check_available() should be True'
57
58 def start_process_test(self):
59 """
60 Test the start_process() of KeyNote
61 """
62 # GIVEN: A boolean value set to true
63 # WHEN: We "convert" it to a bool
64 self.keynote_controller.start_process()
65 # THEN: The process should not be None
66 assert self.keynote_controller.process is not None, u'The result of start_process() should be True'
67
68 def load_presentation_test(self):
69 """
70 Test loading a document in KeyNote
71 """
72 # GIVEN: the filename
73 self.doc = KeynoteDocument(self.keynote_controller,self.file_name)
74 # WHEN: loading the filename
75 self.doc.load_presentation()
76 result = self.doc.is_loaded()
77 # THEN: result should be true
78 assert result is True, u'The KeyNote should load document'
79 assert self.keynote_controller.docs.count() != 0, 'The keynote_controller.docs should have one document.'
80
81 def close_presentation_test(self):
82 """
83 Test closing a document in KeyNote
84 """
85 # GIVEN: loading the filename
86 self.doc = KeynoteDocument(self.keynote_controller,self.file_name)
87 self.doc.load_presentation()
88 # WHEN: closing the filename
89 self.doc.close_presentation()
90 result = self.doc.is_loaded()
91 # THEN: result should be true
92 assert result is False, u'The KeyNote should close document'
93 assert self.keynote_controller.docs.count() == 0, 'The keynote_controller.docs should have 0 documents.'
094
=== added file 'tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py'
--- tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py 2013-10-26 22:59:24 +0000
@@ -0,0 +1,93 @@
1"""
2This module contains tests for the PowerpointController class of the Presentations plugin.
3"""
4
5from unittest import TestCase
6
7from tests.functional import MagicMock
8import os
9from openlp.plugins.presentations.lib.powerpointmaccontroller import PowerpointController, PowerpointDocument
10
11RESOURCES_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
12
13# TODO: write tests for classes
14# - PowerpointController
15# - PowerpointDocument
16
17class TestPowerpointController(TestCase):
18 """
19 Test the PowerpointController class
20 """
21 def setUp(self):
22 """
23 Set up the PowerpointController
24 """
25 presentation_controller = MagicMock()
26 presentation_controller.settings_section = 'presentations'
27 self.powerpoint_controller = PowerpointController(presentation_controller)
28 self.file_name = os.path.join(RESOURCES_PATH,'test.pptx')
29 self.doc = PowerpointDocument(self.powerpoint_controller,self.file_name)
30 self.doc.presentation_deleted()
31
32 def kill_test(self):
33 """
34 Test running the kill() method with an PowerpointController
35 """
36 # GIVEN: A PowerpointController instance and a list of documents
37 presentation_controller = MagicMock()
38 presentation_controller.settings_section = 'presentations'
39 powerpoint_controller = PowerpointController(presentation_controller)
40 ppt_document = MagicMock()
41 powerpoint_controller.docs.append(ppt_document)
42 # WHEN: we run kill()
43 powerpoint_controller.kill()
44 # THEN: all docs should be deleted from controller
45 assert powerpoint_controller.docs.count() == 0, 'The powerpoint_controller should close all documents.'
46 assert powerpoint_controller.process in None, 'The powerpoint_controller should shout down PPT application.'
47
48 def verify_installation_test(self):
49 """
50 Test the installation of PPT
51 """
52 # GIVEN: A boolean value set to true
53 # WHEN: We "convert" it to a bool
54 is_installed = self.powerpoint_controller.check_available()
55 # THEN: We should get back a True bool
56 assert is_installed is True, u'The result of check_available() should be True'
57
58 def start_process_test(self):
59 """
60 Test the start_process() of PPT
61 """
62 # GIVEN: A boolean value set to true
63 # WHEN: We "convert" it to a bool
64 self.powerpoint_controller.start_process()
65 # THEN: The process should not be None
66 assert self.powerpoint_controller.process is not None, u'The result of start_process() should be True'
67
68 def load_presentation_test(self):
69 """
70 Test loading a document in PPT
71 """
72 # GIVEN: the filename
73 self.doc = PowerpointDocument(self.powerpoint_controller,self.file_name)
74 # WHEN: loading the filename
75 self.doc.load_presentation()
76 result = self.doc.is_loaded()
77 # THEN: result should be true
78 assert result is True, u'The PPT should load document'
79 assert self.powerpoint_controller.docs.count() != 0, 'The powerpoint_controller.docs should have one document.'
80
81 def close_presentation_test(self):
82 """
83 Test closing a document in PPT
84 """
85 # GIVEN: loading the filename
86 self.doc = PowerpointDocument(self.powerpoint_controller,self.file_name)
87 self.doc.load_presentation()
88 # WHEN: closing the filename
89 self.doc.close_presentation()
90 result = self.doc.is_loaded()
91 # THEN: result should be true
92 assert result is False, u'The PPT should close document'
93 assert self.powerpoint_controller.docs.count() == 0, 'The powerpoint_controller.docs should have 0 documents.'