Merge lp:~marmyshev/openlp/presentation into lp:openlp
- presentation
- Merge into trunk
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 | ||||
Related bugs: |
|
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.
Commit message
Description of the change
Add support to load presentations with PowerPoint and Keynote on Mac OS X.
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Will need to be approved by matysek_
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/
Thanks
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/
self.
File "/Users/
self.
File "/Users/
doc.
File "/Users/
self.
File "/Users/
for filename in os.listdir(
OSError: [Errno 2] No such file or directory: '/Users/
--- System information ---
Platform: Darwin-
--- 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: -
matysek (mzibricky) : Posted in a previous version of this proposal | # |
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 :)
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/
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/
> please reload."
> --
> https:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
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?
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:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Any progress on this?
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
- You have a conflict in 'openlp/
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, ...).
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. :)
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.
61 +
62 +class KeynoteControll
Before and after the "log = " should be two blank lines
106 + if self.process and len(self.
When dealing with lists do "if not my_list" instead of "if len(my_list) > 0"
387 + text = ''
391 + text += shape.TextFrame
If not explicit wanted do not use strings; use unicode strings: u''
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.
2013-03-23 13:22:37,140 openlp.
2013-03-23 13:22:37,141 openlp.
2013-03-23 13:22:37,141 openlp.
2013-03-23 13:22:37,142 openlp.
2013-03-23 13:22:37,145 openlp.
2013-03-23 13:22:37,146 presentationplugin WARNING Failed to start controller process
2013-03-23 13:22:37,146 openlp.
2013-03-23 13:22:37,146 presentationplugin WARNING Failed to start controller process
2013-03-23 13:22:37,148 openlp.
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.
463 + def check_available
464 + """
465 + PowerPoint is able to run on this machine
466 + """
467 + log.debug(
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.
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.'
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.
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/
openlp/
(Or search for "TODO Presentation plugin is not yet working on Mac OS X." in the source).
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
168 + except appscript.
169 + pass
Please log that the app could not be launched.
285 + except appscript.
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_
608 + self.presentati
Should be self.presentati
(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_
841 + text += shape.text_
842 + return text
Better do:
return u'\n'.join(
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'PresentationM
914 + u'PresentationM
915 + u'PresentationM
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 ;) ).
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_
Agree with all other comments to my code. Will fix it soon.
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_
> 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 ;)
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.
> 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)
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal | # |
304-305 not needed to log.
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
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.
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:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
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:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
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.
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.
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
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?
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.
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.
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.
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:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
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.
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal | # |
Guys, should i do here something else for merging it?
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.
matysek (mzibricky) wrote : Posted in a previous version of this proposal | # |
Related bug reports: #1168495 #1168493
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:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
matysek (mzibricky) wrote : Posted in a previous version of this proposal | # |
Ok, I will try to look at the create_
What documents do you use for testing?
What is your office version? 2011?
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_
> What documents do you use for testing?
> What is your office version? 2011?
> --
> https:/
> You are the owner of lp:~marmyshev/openlp/presentation.
>
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.
The following directory and its parent directories are just empty (lecture22.ppt is the name of the presentation file)
~/Library/
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?
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Are you still working on this?
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.
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?
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
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.
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?
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?
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://
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.
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.
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal | # |
I think now this should work well with thumbnails for PPT.
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.
matysek (mzibricky) wrote : Posted in a previous version of this proposal | # |
I get the following stacktrace when trying to run openlp from this branch:
$ python openlp.py
WARNING: bool Phonon:
Traceback (most recent call last):
File "/opt/openlp_
msg = self.format(record)
File "/opt/openlp_
return fmt.format(record)
File "/opt/openlp_
record.exc_text = self.formatExce
File "/opt/openlp_
traceback.
File "/opt/openlp_
for value, tb in values:
File "/opt/openlp_
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/
sys.
File "/Users/
Registry(
File "/Users/
result = function(*args, **kwargs)
File "/Users/
self.
File "/Users/
plugin.
File "/Users/
super(
File "/Users/
self.
File "/Users/
self.
File "/Users/
if self.controller
File "/Users/
return self.is_available()
File "/Users/
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal | # |
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_
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:
> plugin could not be loaded
> Traceback (most recent call last):
> File
> "/opt/openlp_
> line 937, in emit
> msg = self.format(record)
> File
> "/opt/openlp_
> line 808, in format
> return fmt.format(record)
> File
> "/opt/openlp_
> line 554, in format
> record.exc_text = self.formatExce
> File
> "/opt/openlp_
> line 504, in formatException
> traceback.
> File
> "/opt/openlp_
> line 156, in print_exception
> for value, tb in values:
> File
> "/opt/openlp_
> 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/
> 326, in main
> sys.exit(
> File
> "/Users/
> 137, in run
> Registry(
> File
> "/Users/
> line 159, in execute
> result = function(*args, **kwargs)
> File
> "/Users/
> line 86, in bootstrap_
> self.initialise
> File
> "/Users/
> line 201, in initialise_plugins
> plugin.initialise()
> File
> "/Users/
> line 91, in initialise
> super(Presentat
> File
> "/Users/
> line 296, in initialise
> self.media_
> File
> "/Users/
> line 127, in initialise
> self.populate_
> File
>...
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?
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?
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.
Btw, I'm testing a .ppt file if that makes a difference. Did you test only pptx files?
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
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?
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.
What do you have in syntax?
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?
matysek (mzibricky) wrote : Posted in a previous version of this proposal | # |
I upgraded macoffice to version 14.1 and now the presentation.
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.
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:/
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?
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
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.
matysek (mzibricky) wrote : Posted in a previous version of this proposal | # |
It still works.
Dmitriy Marmyshev (marmyshev) wrote : Posted in a previous version of this proposal | # |
matysek: please approve it in actual proposal version :)
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://
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_
msg = self.format(record)
File "/opt/openlp_
return fmt.format(record)
File "/opt/openlp_
record.exc_text = self.formatExce
File "/opt/openlp_
traceback.
File "/opt/openlp_
for value, tb in values:
File "/opt/openlp_
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/
self.
File "/Users/
self.
File "/Users/
'%s_start' % service_
File "/Users/
result = function(*args, **kwargs)
File "/Users/
if self.handler == self.media_
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://
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!
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
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2013-09-14 02:42:12 +0000 |
3 | +++ .bzrignore 2013-10-26 22:59:24 +0000 |
4 | @@ -2,6 +2,7 @@ |
5 | *.*~ |
6 | \#*\# |
7 | *.eric4project |
8 | +*.eric5project |
9 | *.ropeproject |
10 | *.e4* |
11 | .eric4project |
12 | |
13 | === modified file 'openlp/core/lib/pluginmanager.py' |
14 | --- openlp/core/lib/pluginmanager.py 2013-10-13 13:51:13 +0000 |
15 | +++ openlp/core/lib/pluginmanager.py 2013-10-26 22:59:24 +0000 |
16 | @@ -94,11 +94,6 @@ |
17 | present_plugin_dir = os.path.join(self.base_path, 'presentations') |
18 | log.debug('finding plugins in %s at depth %d', str(self.base_path), start_depth) |
19 | for root, dirs, files in os.walk(self.base_path): |
20 | - if sys.platform == 'darwin' and root.startswith(present_plugin_dir): |
21 | - # TODO Presentation plugin is not yet working on Mac OS X. |
22 | - # For now just ignore it. The following code will ignore files from the presentation plugin directory |
23 | - # and thereby never import the plugin. |
24 | - continue |
25 | for name in files: |
26 | if name.endswith('.py') and not name.startswith('__'): |
27 | path = os.path.abspath(os.path.join(root, name)) |
28 | |
29 | === modified file 'openlp/core/ui/firsttimeform.py' |
30 | --- openlp/core/ui/firsttimeform.py 2013-10-13 21:07:28 +0000 |
31 | +++ openlp/core/ui/firsttimeform.py 2013-10-26 22:59:24 +0000 |
32 | @@ -414,10 +414,7 @@ |
33 | self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...')) |
34 | self._set_plugin_status(self.songs_check_box, 'songs/status') |
35 | self._set_plugin_status(self.bible_check_box, 'bibles/status') |
36 | - # TODO Presentation plugin is not yet working on Mac OS X. |
37 | - # For now just ignore it. |
38 | - if sys.platform != 'darwin': |
39 | - self._set_plugin_status(self.presentation_check_box, 'presentations/status') |
40 | + self._set_plugin_status(self.presentation_check_box, 'presentations/status') |
41 | self._set_plugin_status(self.image_check_box, 'images/status') |
42 | self._set_plugin_status(self.media_check_box, 'media/status') |
43 | self._set_plugin_status(self.remote_check_box, 'remotes/status') |
44 | |
45 | === modified file 'openlp/core/ui/firsttimewizard.py' |
46 | --- openlp/core/ui/firsttimewizard.py 2013-10-13 21:07:28 +0000 |
47 | +++ openlp/core/ui/firsttimewizard.py 2013-10-26 22:59:24 +0000 |
48 | @@ -93,13 +93,10 @@ |
49 | self.image_check_box.setChecked(True) |
50 | self.image_check_box.setObjectName('image_check_box') |
51 | self.plugin_layout.addWidget(self.image_check_box) |
52 | - # TODO Presentation plugin is not yet working on Mac OS X. |
53 | - # For now just ignore it. |
54 | - if sys.platform != 'darwin': |
55 | - self.presentation_check_box = QtGui.QCheckBox(self.plugin_page) |
56 | - self.presentation_check_box.setChecked(True) |
57 | - self.presentation_check_box.setObjectName('presentation_check_box') |
58 | - self.plugin_layout.addWidget(self.presentation_check_box) |
59 | + self.presentation_check_box = QtGui.QCheckBox(self.plugin_page) |
60 | + self.presentation_check_box.setChecked(True) |
61 | + self.presentation_check_box.setObjectName('presentation_check_box') |
62 | + self.plugin_layout.addWidget(self.presentation_check_box) |
63 | self.media_check_box = QtGui.QCheckBox(self.plugin_page) |
64 | self.media_check_box.setChecked(True) |
65 | self.media_check_box.setObjectName('media_check_box') |
66 | @@ -219,10 +216,7 @@ |
67 | self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides')) |
68 | self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bible')) |
69 | self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Images')) |
70 | - # TODO Presentation plugin is not yet working on Mac OS X. |
71 | - # For now just ignore it. |
72 | - if sys.platform != 'darwin': |
73 | - self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations')) |
74 | + self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations')) |
75 | self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)')) |
76 | self.remote_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access')) |
77 | self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Monitor Song Usage')) |
78 | |
79 | === added file 'openlp/plugins/presentations/lib/keynotemaccontroller.py' |
80 | --- openlp/plugins/presentations/lib/keynotemaccontroller.py 1970-01-01 00:00:00 +0000 |
81 | +++ openlp/plugins/presentations/lib/keynotemaccontroller.py 2013-10-26 22:59:24 +0000 |
82 | @@ -0,0 +1,360 @@ |
83 | +# -*- coding: utf-8 -*- |
84 | +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 |
85 | + |
86 | +############################################################################### |
87 | +# OpenLP - Open Source Lyrics Projection # |
88 | +# --------------------------------------------------------------------------- # |
89 | +# Copyright (c) 2008-2012 Raoul Snyman # |
90 | +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # |
91 | +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # |
92 | +# Meinert Jordan, Armin Köhler, Eric Ludin, Edwin Lunando, Brian T. Meyer, # |
93 | +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # |
94 | +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # |
95 | +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # |
96 | +# Frode Woldsund, Martin Zibricky # |
97 | +# --------------------------------------------------------------------------- # |
98 | +# This program is free software; you can redistribute it and/or modify it # |
99 | +# under the terms of the GNU General Public License as published by the Free # |
100 | +# Software Foundation; version 2 of the License. # |
101 | +# # |
102 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
103 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
104 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
105 | +# more details. # |
106 | +# # |
107 | +# You should have received a copy of the GNU General Public License along # |
108 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
109 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
110 | +############################################################################### |
111 | + |
112 | +import os |
113 | +import logging |
114 | +import appscript |
115 | + |
116 | +from openlp.core.common import Settings |
117 | +from openlp.core.lib import ScreenList |
118 | +from .presentationcontroller import PresentationController, PresentationDocument |
119 | + |
120 | + |
121 | +log = logging.getLogger(__name__) |
122 | + |
123 | + |
124 | +class KeynoteController(PresentationController): |
125 | + """ |
126 | + Class to control interactions with KeyNote Presentations |
127 | + It creates the runtime Environment , Loads the and Closes the Presentation |
128 | + As well as triggering the correct activities based on the users input |
129 | + """ |
130 | + log.info('KeynoteController loaded') |
131 | + |
132 | + def __init__(self, plugin): |
133 | + """ |
134 | + Initialise the class |
135 | + """ |
136 | + log.debug('Initialising') |
137 | + super(KeynoteController, self).__init__(plugin, 'Keynote', KeynoteDocument) |
138 | + self.supports = ['key'] |
139 | + self.process = None |
140 | + |
141 | + def check_available(self): |
142 | + """ |
143 | + KeyNote is able to run on this machine |
144 | + """ |
145 | + log.debug('check_available') |
146 | + try: |
147 | + self.process = appscript.app('Keynote') |
148 | + except appscript.ApplicationNotFoundError: |
149 | + return False |
150 | + self.kill() |
151 | + return True |
152 | + |
153 | + def start_process(self): |
154 | + """ |
155 | + Loads KeyNote process |
156 | + """ |
157 | + log.debug('start_process') |
158 | + if not self.process or not self.process.isrunning(): |
159 | + self.process = appscript.app('Keynote') |
160 | + self.process.relaunchmode = 'limited' #'always' |
161 | + self.process.launch() |
162 | + self.apply_app_settings() |
163 | + |
164 | + def kill(self): |
165 | + """ |
166 | + Called at system exit to clean up any running presentations |
167 | + """ |
168 | + log.debug('Kill Keynote') |
169 | + while self.docs and self.process.isrunning(): |
170 | + self.docs[0].close_presentation() |
171 | + if self.process is None or not self.process.isrunning(): |
172 | + return |
173 | + try: |
174 | + total = self.process.slideshows() |
175 | + if self.process and total != appscript.k.missing_value and len(total) > 0: |
176 | + return |
177 | + self.process.quit(saving = appscript.k.ask) |
178 | + except appscript.CantLaunchApplicationError: |
179 | + log.debug('Kill Keynote failed') |
180 | + self.process = None |
181 | + |
182 | + def apply_app_settings(self): |
183 | + """ |
184 | + Apply settings for Keynote |
185 | + PresentationModeEnableFeedbackDisplay = True if in settings of OpenLP show presenter view = True |
186 | + PresentationModeUseSecondary = 1 if OpenLP monitor for output = Screen 2 |
187 | + """ |
188 | + openlp_settings = Settings('openlp.org','OpenLP') |
189 | + keynote_settings = Settings('apple', 'iWork.Keynote') |
190 | + use_secondary = int(keynote_settings.value('PresentationModeUseSecondary')) |
191 | + monitor = openlp_settings.value( 'core/monitor') |
192 | + override_position = openlp_settings.value( 'core/override position') |
193 | + if not override_position and use_secondary != monitor: |
194 | + keynote_settings.setValue('PresentationModeUseSecondary', monitor) |
195 | + elif override_position and use_secondary != 0: |
196 | + keynote_settings.setValue('PresentationModeUseSecondary', '0') |
197 | + show_presenter_view = openlp_settings.value(self.plugin.settings_section + '/show presenter view') |
198 | + keynote_feedback_display = keynote_settings.value('PresentationModeEnableFeedbackDisplay') |
199 | + if show_presenter_view != keynote_feedback_display: |
200 | + keynote_settings.setValue('PresentationModeEnableFeedbackDisplay', show_presenter_view) |
201 | + play_well_with_others = keynote_settings.value('PresentationModePlayWellWithOthers') |
202 | + if not play_well_with_others: |
203 | + keynote_settings.setValue('PresentationModePlayWellWithOthers', True) |
204 | + |
205 | + |
206 | +class KeynoteDocument(PresentationDocument): |
207 | + """ |
208 | + Class which holds information and controls a single presentation |
209 | + """ |
210 | + |
211 | + def __init__(self, controller, presentation): |
212 | + """ |
213 | + Constructor, store information about the file and initialise |
214 | + """ |
215 | + log.debug('Init Presentation Keynote') |
216 | + super(KeynoteDocument, self).__init__(controller, presentation) |
217 | + self.presentation = None |
218 | + |
219 | + def load_presentation(self): |
220 | + """ |
221 | + Called when a presentation is added to the SlideController. |
222 | + Opens the Keynote file using the process created earlier. |
223 | + """ |
224 | + log.debug('load_presentation') |
225 | + if not self.controller.process or not self.controller.process.isrunning(): |
226 | + self.controller.start_process() |
227 | + try: |
228 | + self.controller.process.open(self.filepath) |
229 | + except appscript.CommandError: |
230 | + log.debug('Keynote open failed') |
231 | + return False |
232 | + slideshows = self.controller.process.slideshows() |
233 | + for slideshow in slideshows: |
234 | + path = slideshow.path() |
235 | + if self.filepath == path: |
236 | + self.presentation = slideshow |
237 | + self.create_thumbnails() |
238 | + return True |
239 | + self.presentation = None |
240 | + return False |
241 | + |
242 | + def create_thumbnails(self): |
243 | + """ |
244 | + Create the thumbnail images for the current presentation. |
245 | + """ |
246 | + log.debug('create_thumbnails') |
247 | + if self.check_thumbnails(): |
248 | + return |
249 | + thumbnail_folder = self.get_thumbnail_folder() |
250 | + if not os.path.exists(thumbnail_folder): |
251 | + os.makedirs(thumbnail_folder) |
252 | + try: |
253 | + self.controller.process.open(self.filepath) |
254 | + except appscript.CommandError: |
255 | + log.debug('KeyNote open failed') |
256 | + return |
257 | + temp_dir = self.controller.thumbnail_folder |
258 | + keystroke = os.path.join(temp_dir, 'temp' + self.controller.thumbnail_prefix) |
259 | + self.controller.process.activate() |
260 | + appscript.app('System Events').processes['Keynote'].menu_bars[1].menu_bar_items[3].menus.menu_items[11].click() |
261 | + appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].tool_bars.buttons[4].click() |
262 | + appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].radio_groups[1].radio_buttons[1].click() |
263 | + appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].pop_up_buttons[1].click() |
264 | + appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].pop_up_buttons[1]\ |
265 | + .menus.menu_items[2].click() |
266 | + appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].buttons[2].click() |
267 | + appscript.app('System Events').processes['Keynote'].keystroke(keystroke) |
268 | + appscript.app('System Events').processes['Keynote'].key_code(36) |
269 | + appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].buttons[1].click() |
270 | + self.controller.plugin._main_window.activateWindow() |
271 | + slide_no = 0 |
272 | + for filename in os.listdir(temp_dir): |
273 | + full_filename = os.path.join(temp_dir, filename) |
274 | + if not os.path.isfile(full_filename) or not filename.endswith('.png') or filename == 'icon.png': |
275 | + continue |
276 | + slide_no = slide_no + 1 |
277 | + if not filename.startswith(self.controller.thumbnail_prefix): |
278 | + path = os.path.join(thumbnail_folder, |
279 | + self.controller.thumbnail_prefix + str(slide_no) + '.png') |
280 | + try: |
281 | + os.rename(full_filename, path) |
282 | + except: |
283 | + open(path,'w').write(open(full_filename,'r').read()) |
284 | + os.unlink(full_filename) |
285 | + |
286 | + def close_presentation(self): |
287 | + """ |
288 | + Close presentation and clean up objects. This is triggered by a new |
289 | + object being added to SlideController or OpenLP being shut down. |
290 | + """ |
291 | + log.debug('close_presentation') |
292 | + if self.presentation: |
293 | + try: |
294 | + self.presentation.close() |
295 | + except appscript.CommandError: |
296 | + log.debug('Could not close the presentation') |
297 | + self.presentation = None |
298 | + self.controller.remove_doc(self) |
299 | + |
300 | + def is_loaded(self): |
301 | + """ |
302 | + Returns ``True`` if a presentation is loaded. |
303 | + """ |
304 | + log.debug('is_loaded') |
305 | + try: |
306 | + if not self.controller.process.isrunning(): |
307 | + return False |
308 | + windows = self.controller.process.windows() |
309 | + if len(windows) == 0: |
310 | + return False |
311 | + slideshows = self.controller.process.slideshows() |
312 | + if len(slideshows) == 0: |
313 | + return False |
314 | + except: |
315 | + return False |
316 | + for slideshow in slideshows: |
317 | + path = slideshow.path() |
318 | + if self.filepath == path: |
319 | + return True |
320 | + return False |
321 | + |
322 | + def is_active(self): |
323 | + """ |
324 | + Returns ``True`` if a presentation is currently active. |
325 | + """ |
326 | + log.debug('is_active') |
327 | + if not self.is_loaded(): |
328 | + return False |
329 | + try: |
330 | + if not self.presentation.playing(): |
331 | + return False |
332 | + except appscript.CommandError: |
333 | + return False |
334 | + return True |
335 | + |
336 | + def unblank_screen(self): |
337 | + """ |
338 | + Unblanks (restores) the presentation. |
339 | + """ |
340 | + log.debug('unblank_screen') |
341 | + if self.is_blank(): |
342 | + self.presentation.start_presentation() |
343 | + |
344 | + def blank_screen(self): |
345 | + """ |
346 | + Blanks the screen. |
347 | + """ |
348 | + log.debug('blank_screen') |
349 | + self.presentation.stop_slideshow() |
350 | + |
351 | + def is_blank(self): |
352 | + """ |
353 | + Returns ``True`` if screen is blank. |
354 | + """ |
355 | + log.debug('is_blank') |
356 | + if self.is_active(): |
357 | + return not self.presentation.playing() |
358 | + else: |
359 | + return False |
360 | + |
361 | + def stop_presentation(self): |
362 | + """ |
363 | + Stops the current presentation and hides the output. |
364 | + """ |
365 | + log.debug('stop_presentation') |
366 | + self.presentation.stop_slideshow() |
367 | + |
368 | + |
369 | + def start_presentation(self): |
370 | + """ |
371 | + Starts a presentation from the beginning. |
372 | + """ |
373 | + log.debug('start_presentation') |
374 | + if not self.is_active(): |
375 | + self.controller.apply_app_settings() |
376 | + try: |
377 | + self.presentation.start() |
378 | + except appscript.CommandError: |
379 | + return |
380 | + rect = ScreenList().current['size'] |
381 | + top = rect.y() |
382 | + height = rect.height() |
383 | + left_position = rect.x() |
384 | + width = rect.width() |
385 | + self.controller.process.windows[1].bounds.set([left_position, top, left_position + width, top + height]) |
386 | + |
387 | + def get_slide_number(self): |
388 | + """ |
389 | + Returns the current slide number. |
390 | + """ |
391 | + log.debug('get_slide_number') |
392 | + return self.presentation.current_slide().slide_number() |
393 | + |
394 | + def get_slide_count(self): |
395 | + """ |
396 | + Returns total number of slides. |
397 | + """ |
398 | + log.debug('get_slide_count') |
399 | + slides = self.presentation.slides() |
400 | + return len(slides) |
401 | + |
402 | + def goto_slide(self, slideno): |
403 | + """ |
404 | + Moves to a specific slide in the presentation. |
405 | + """ |
406 | + log.debug('goto_slide') |
407 | + slide = self.presentation.slides()[slideno-1] |
408 | + self.presentation.show(slide) |
409 | + |
410 | + def next_step(self): |
411 | + """ |
412 | + Triggers the next effect of slide on the running presentation. |
413 | + """ |
414 | + log.debug('next_step') |
415 | + self.presentation.show_next() |
416 | + if self.get_slide_number() > self.get_slide_count(): |
417 | + self.previous_step() |
418 | + |
419 | + def previous_step(self): |
420 | + """ |
421 | + Triggers the previous slide on the running presentation. |
422 | + """ |
423 | + log.debug('previous_step') |
424 | + self.presentation.show_previous() |
425 | + |
426 | + def get_slide_text(self, slide_no): |
427 | + """ |
428 | + Returns the text on the slide. |
429 | + |
430 | + ``slide_no`` |
431 | + The slide the text is required for, starting at 1. |
432 | + """ |
433 | + return self.presentation.slides[slide_no].body |
434 | + |
435 | + def get_slide_notes(self, slide_no): |
436 | + """ |
437 | + Returns the text on the slide. |
438 | + |
439 | + ``slide_no`` |
440 | + The slide the notes are required for, starting at 1. |
441 | + """ |
442 | + return self.presentation.slides[slide_no].notes |
443 | |
444 | === added file 'openlp/plugins/presentations/lib/powerpointmaccontroller.py' |
445 | --- openlp/plugins/presentations/lib/powerpointmaccontroller.py 1970-01-01 00:00:00 +0000 |
446 | +++ openlp/plugins/presentations/lib/powerpointmaccontroller.py 2013-10-26 22:59:24 +0000 |
447 | @@ -0,0 +1,397 @@ |
448 | +# -*- coding: utf-8 -*- |
449 | +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 |
450 | + |
451 | +############################################################################### |
452 | +# OpenLP - Open Source Lyrics Projection # |
453 | +# --------------------------------------------------------------------------- # |
454 | +# Copyright (c) 2008-2012 Raoul Snyman # |
455 | +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # |
456 | +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # |
457 | +# Meinert Jordan, Armin Köhler, Eric Ludin, Edwin Lunando, Brian T. Meyer, # |
458 | +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # |
459 | +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # |
460 | +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # |
461 | +# Frode Woldsund, Martin Zibricky # |
462 | +# --------------------------------------------------------------------------- # |
463 | +# This program is free software; you can redistribute it and/or modify it # |
464 | +# under the terms of the GNU General Public License as published by the Free # |
465 | +# Software Foundation; version 2 of the License. # |
466 | +# # |
467 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
468 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
469 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
470 | +# more details. # |
471 | +# # |
472 | +# You should have received a copy of the GNU General Public License along # |
473 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
474 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
475 | +############################################################################### |
476 | + |
477 | +import os |
478 | +import logging |
479 | +import shutil |
480 | + |
481 | +import appscript |
482 | + |
483 | +from openlp.core.common import Settings |
484 | +from openlp.core.lib import ScreenList |
485 | +from .presentationcontroller import PresentationController, PresentationDocument |
486 | + |
487 | + |
488 | +log = logging.getLogger(__name__) |
489 | + |
490 | + |
491 | +class PowerpointController(PresentationController): |
492 | + """ |
493 | + Class to control interactions with PowerPoint Presentations |
494 | + It creates the runtime Environment , Loads the and Closes the Presentation |
495 | + As well as triggering the correct activities based on the users input |
496 | + """ |
497 | + log.info(u'PowerpointController loaded') |
498 | + |
499 | + def __init__(self, plugin): |
500 | + """ |
501 | + Initialise the class |
502 | + """ |
503 | + log.debug('Initialising') |
504 | + super(PowerpointController, self).__init__(plugin, 'Powerpoint', PowerpointDocument) |
505 | + self.supports = ['ppt', 'pps', 'pptx', 'ppsx'] |
506 | + self.process = None |
507 | + |
508 | + def check_available(self): |
509 | + """ |
510 | + PowerPoint is able to run on this machine |
511 | + """ |
512 | + log.debug('check_available') |
513 | + try: |
514 | + self.process = appscript.app(id='com.microsoft.powerpoint') |
515 | + except appscript.ApplicationNotFoundError: |
516 | + return False |
517 | + self.kill() |
518 | + return True |
519 | + |
520 | + def start_process(self): |
521 | + """ |
522 | + Loads PowerPoint process |
523 | + """ |
524 | + log.debug('start_process') |
525 | + if not self.process or not self.process.isrunning(): |
526 | + self.process = appscript.app(id='com.microsoft.powerpoint') |
527 | + self.process.relaunchmode = 'limited' #'always' |
528 | + self.process.launch() |
529 | + self.apply_app_settings() |
530 | + |
531 | + def kill(self): |
532 | + """ |
533 | + Called at system exit to clean up any running presentations |
534 | + """ |
535 | + log.debug('Kill Powerpoint') |
536 | + while self.docs and self.process.isrunning(): |
537 | + self.docs[0].close_presentation() |
538 | + if self.process is None or not self.process.isrunning(): |
539 | + return |
540 | + try: |
541 | + total = self.process.presentations() |
542 | + if self.process and total != appscript.k.missing_value and len(total) > 0: |
543 | + return |
544 | + self.process.quit(saving = appscript.k.ask) |
545 | + except appscript.CantLaunchApplicationError: |
546 | + log.debug('Kill Keynote failed') |
547 | + self.process = None |
548 | + |
549 | + def apply_app_settings(self): |
550 | + """ |
551 | + Apply settings for PowerPoint |
552 | + 14\Options\Options\Save graphics screen heigth = 240 |
553 | + 14\Options\Options\Save graphics screen width = 320 |
554 | + 14\Options\Options\Save only current slide graphics = 0 |
555 | + |
556 | + """ |
557 | + #TODO: add settings for different versions of MS PPT |
558 | + pass |
559 | + |
560 | + |
561 | +class PowerpointDocument(PresentationDocument): |
562 | + """ |
563 | + Class which holds information and controls a single presentation |
564 | + """ |
565 | + |
566 | + def __init__(self, controller, presentation): |
567 | + """ |
568 | + Constructor, store information about the file and initialise |
569 | + """ |
570 | + log.debug('Init Presentation Powerpoint') |
571 | + super(PowerpointDocument, self).__init__(controller, presentation) |
572 | + self.presentation = None |
573 | + |
574 | + def load_presentation(self): |
575 | + """ |
576 | + Called when a presentation is added to the SlideController. |
577 | + Opens the PowerPoint file using the process created earlier. |
578 | + """ |
579 | + log.debug('load_presentation') |
580 | + if not self.controller.process or not self.controller.process.isrunning(): |
581 | + self.controller.start_process() |
582 | + try: |
583 | + self.controller.process.open(self.filepath) |
584 | + except appscript.CommandError: |
585 | + log.debug('PPT open failed') |
586 | + return False |
587 | + presentations = self.controller.process.presentations() |
588 | + for presentation in presentations: |
589 | + full_name = presentation.full_name() |
590 | + full_name = full_name.replace('Macintosh HD', '') |
591 | + full_name = full_name.replace(':', '/') |
592 | + if self.filepath == full_name: |
593 | + self.presentation = presentation |
594 | + self.create_thumbnails() |
595 | + return True |
596 | + return False |
597 | + |
598 | + def create_thumbnails(self): |
599 | + """ |
600 | + Create the thumbnail images for the current presentation. |
601 | + """ |
602 | + log.debug('create_thumbnails') |
603 | + if self.check_thumbnails(): |
604 | + return |
605 | + thumbnail_folder = self.get_thumbnail_folder() |
606 | + self.presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG) |
607 | + slide_no = 0 |
608 | + self.move_thumbnails(thumbnail_folder, slide_no, thumbnail_folder) |
609 | + |
610 | + def move_thumbnails(self, thumbnail_folder, slide_no, temp_dir): |
611 | + """ |
612 | + Move the thumbnail images from subdirectories to right path. |
613 | + """ |
614 | + if not os.path.isdir(temp_dir): |
615 | + return |
616 | + for filename in os.listdir(temp_dir): |
617 | + full_filename = os.path.join(temp_dir, filename) |
618 | + if os.path.isdir(full_filename): |
619 | + self.move_thumbnails(thumbnail_folder, slide_no, full_filename) |
620 | + elif os.path.isfile(full_filename) and filename.endswith('.png') and not filename == 'icon.png': |
621 | + slide_no = slide_no + 1 |
622 | + new_name = os.path.join(thumbnail_folder, self.controller.thumbnail_prefix + str(slide_no) + '.png') |
623 | + if full_filename == new_name \ |
624 | + or full_filename.startswith(os.path.join(thumbnail_folder, self.controller.thumbnail_prefix)): |
625 | + continue |
626 | + try: |
627 | + os.rename(full_filename, new_name) |
628 | + except: |
629 | + open(new_name,'w').write(open(full_filename,'r').read()) |
630 | + os.unlink(full_filename) |
631 | + if temp_dir != thumbnail_folder: |
632 | + try: |
633 | + shutil.rmtree(temp_dir) |
634 | + except: |
635 | + pass |
636 | + |
637 | + def close_presentation(self): |
638 | + """ |
639 | + Close presentation and clean up objects. This is triggered by a new |
640 | + object being added to SlideController or OpenLP being shut down. |
641 | + """ |
642 | + log.debug('close_presentation') |
643 | + if self.presentation: |
644 | + try: |
645 | + self.presentation.close() |
646 | + except appscript.CommandError: |
647 | + log.debug('Could not close the presentation') |
648 | + self.presentation = None |
649 | + self.controller.remove_doc(self) |
650 | + |
651 | + def is_loaded(self): |
652 | + """ |
653 | + Returns ``True`` if a presentation is loaded. |
654 | + """ |
655 | + log.debug('is_loaded') |
656 | + try: |
657 | + if not self.controller.process.isrunning(): |
658 | + return False |
659 | + if len(self.controller.process.document_windows()) == 0: |
660 | + return False |
661 | + presentations = self.controller.process.presentations() |
662 | + if len(presentations) == 0: |
663 | + return False |
664 | + except: |
665 | + return False |
666 | + for presentation in presentations: |
667 | + full_name = presentation.full_name() |
668 | + full_name = full_name.replace('Macintosh HD', '') |
669 | + full_name = full_name.replace(':', '/') |
670 | + if self.filepath == full_name: |
671 | + return True |
672 | + return False |
673 | + |
674 | + def is_active(self): |
675 | + """ |
676 | + Returns ``True`` if a presentation is currently active. |
677 | + """ |
678 | + log.debug('is_active') |
679 | + if not self.is_loaded(): |
680 | + return False |
681 | + try: |
682 | + slide_show_window = self.presentation.slide_show_window |
683 | + if slide_show_window is None: |
684 | + return False |
685 | + slide_state = self.presentation.slide_show_window.slideshow_view.slide_state() |
686 | + if slide_state is None or slide_state == appscript.k.missing_value: |
687 | + return False |
688 | + except: |
689 | + return False |
690 | + return True |
691 | + |
692 | + def unblank_screen(self): |
693 | + """ |
694 | + Unblanks (restores) the presentation. |
695 | + """ |
696 | + log.debug('unblank_screen') |
697 | + if self.is_blank(): |
698 | + self.presentation.slide_show_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_running) |
699 | + self.presentation.slide_show_window.slideshow_view.go_to_next_slide() |
700 | + self.presentation.slide_show_window.slideshow_view.go_to_previous_slide() |
701 | + |
702 | + def blank_screen(self): |
703 | + """ |
704 | + Blanks the screen. |
705 | + """ |
706 | + log.debug('blank_screen') |
707 | + self.presentation.slide_show_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_black_screen) |
708 | + |
709 | + def is_blank(self): |
710 | + """ |
711 | + Returns ``True`` if screen is blank. |
712 | + """ |
713 | + log.debug('is_blank') |
714 | + if self.is_active() and self.presentation.slide_show_window.slideshow_view\ |
715 | + .slide_state() is appscript.k.slide_show_state_black_screen: |
716 | + return True |
717 | + else: |
718 | + return False |
719 | + |
720 | + def stop_presentation(self): |
721 | + """ |
722 | + Stops the current presentation and hides the output. |
723 | + """ |
724 | + log.debug('stop_presentation') |
725 | + self.presentation.slide_show_window.slideshow_view.exit_slide_show() |
726 | + |
727 | + |
728 | + def start_presentation(self): |
729 | + """ |
730 | + Starts a presentation from the beginning. |
731 | + """ |
732 | + log.debug('start_presentation') |
733 | + rect = ScreenList().current['size'] |
734 | + ppt_settings = self.presentation.slide_show_settings |
735 | + openlp_settings = Settings("openlp.org","OpenLP") |
736 | + show_presenter_view = openlp_settings.value(self.controller.plugin.settings_section + '/show presenter view') |
737 | + override_position = openlp_settings.value( 'general/override position') |
738 | + if show_presenter_view: |
739 | + ppt_settings.show_type.set(appscript.k.slide_show_type_presenter) |
740 | + elif override_position: |
741 | + ppt_settings.show_type.set(appscript.k.slide_show_type_window) |
742 | + else: |
743 | + ppt_settings.show_type.set(appscript.k.slide_show_type_kiosk) |
744 | + #ppt_settings.show_type.set(appscript.k.slide_show_type_speaker) |
745 | + ppt_window = ppt_settings.run_slide_show() |
746 | + #TODO: set slideshow state = running |
747 | + #if ppt_window.slideshow_view.slide_state() != appscript.k.slide_show_state_running: |
748 | + # ppt_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_running) |
749 | + if not ppt_window or show_presenter_view: |
750 | + return |
751 | + if override_position: |
752 | + top = float(rect.y()) |
753 | + height = float(rect.height()) |
754 | + left_position = float(rect.x()) |
755 | + width = float(rect.width()) |
756 | + ppt_window.top.set(top) |
757 | + ppt_window.height.set(height) |
758 | + ppt_window.left_position.set(left_position) |
759 | + ppt_window.width.set(width) |
760 | + else: |
761 | + #TODO: set output monitor for fullscreen mode |
762 | + pass |
763 | + |
764 | + def get_slide_number(self): |
765 | + """ |
766 | + Returns the current slide number. |
767 | + """ |
768 | + log.debug('get_slide_number') |
769 | + return self.presentation.slide_show_window.slideshow_view.current_show_position() |
770 | + |
771 | + def get_slide_count(self): |
772 | + """ |
773 | + Returns total number of slides. |
774 | + """ |
775 | + log.debug('get_slide_count') |
776 | + return len(self.presentation.slides()) |
777 | + |
778 | + def goto_slide(self, slideno): |
779 | + """ |
780 | + Moves to a specific slide in the presentation. |
781 | + """ |
782 | + log.debug('goto_slide') |
783 | + #FIXME: this works. but needs to fix this code |
784 | + while self.get_slide_number() != slideno: |
785 | + if self.get_slide_number() < slideno: |
786 | + self.presentation.slide_show_window.slideshow_view.go_to_next_slide() |
787 | + else: |
788 | + self.presentation.slide_show_window.slideshow_view.go_to_previous_slide() |
789 | + self.controller.process.activate() |
790 | + |
791 | + def next_step(self): |
792 | + """ |
793 | + Triggers the next effect of slide on the running presentation. |
794 | + """ |
795 | + log.debug('next_step') |
796 | + #TODO: check if slideshow stoped then restart it from current position |
797 | + if self.is_active(): |
798 | + self.presentation.slide_show_window.slideshow_view.go_to_next_slide() |
799 | + self.controller.process.activate() |
800 | + if self.get_slide_number() > self.get_slide_count(): |
801 | + self.previous_step() |
802 | + |
803 | + def previous_step(self): |
804 | + """ |
805 | + Triggers the previous slide on the running presentation. |
806 | + """ |
807 | + log.debug('previous_step') |
808 | + #TODO: check if slideshow stoped then restart it from current position |
809 | + if self.is_active(): |
810 | + self.presentation.slide_show_window.slideshow_view.go_to_previous_slide() |
811 | + self.controller.process.activate() |
812 | + |
813 | + def get_slide_text(self, slide_no): |
814 | + """ |
815 | + Returns the text on the slide. |
816 | + |
817 | + ``slide_no`` |
818 | + The slide the text is required for, starting at 1. |
819 | + """ |
820 | + return _get_text_from_shapes(self.presentation.slides[slide_no-1].shapes) |
821 | + |
822 | + def get_slide_notes(self, slide_no): |
823 | + """ |
824 | + Returns the text on the slide. |
825 | + |
826 | + ``slide_no`` |
827 | + The slide the notes are required for, starting at 1. |
828 | + """ |
829 | + return _get_text_from_shapes( |
830 | + self.presentation.slides[slide_no].notes_page.shapes()) |
831 | + |
832 | +def _get_text_from_shapes(shapes): |
833 | + """ |
834 | + Returns any text extracted from the shapes on a presentation slide. |
835 | + |
836 | + ``shapes`` |
837 | + A set of shapes to search for text. |
838 | + """ |
839 | + text = '' |
840 | + for idx in range(len(shapes)): |
841 | + shape = shapes[idx + 1] |
842 | + if shape.has_text_frame(): |
843 | + text += shape.text_frame.text_range.content() + '\n' |
844 | + return text |
845 | |
846 | === modified file 'openlp/plugins/presentations/lib/presentationtab.py' |
847 | --- openlp/plugins/presentations/lib/presentationtab.py 2013-10-13 20:36:42 +0000 |
848 | +++ openlp/plugins/presentations/lib/presentationtab.py 2013-10-26 22:59:24 +0000 |
849 | @@ -27,6 +27,8 @@ |
850 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
851 | ############################################################################### |
852 | |
853 | +import sys |
854 | + |
855 | from PyQt4 import QtGui |
856 | |
857 | from openlp.core.common import Settings, UiStrings, translate |
858 | @@ -71,6 +73,11 @@ |
859 | self.override_app_check_box = QtGui.QCheckBox(self.advanced_group_box) |
860 | self.override_app_check_box.setObjectName('override_app_check_box') |
861 | self.advanced_layout.addWidget(self.override_app_check_box) |
862 | + self.show_presenter_view_check_box = QtGui.QCheckBox(self.advanced_group_box) |
863 | + self.show_presenter_view_check_box.setObjectName(u'show_presenter_view_check_box') |
864 | + self.advanced_layout.addWidget(self.show_presenter_view_check_box) |
865 | + if not sys.platform.startswith('darwin'): |
866 | + self.show_presenter_view_check_box.setVisible(False) |
867 | self.left_layout.addWidget(self.advanced_group_box) |
868 | self.left_layout.addStretch() |
869 | self.right_layout.addStretch() |
870 | @@ -87,6 +94,8 @@ |
871 | self.advanced_group_box.setTitle(UiStrings().Advanced) |
872 | self.override_app_check_box.setText( |
873 | translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden')) |
874 | + self.show_presenter_view_check_box.setText(translate('PresentationPlugin.PresentationTab', |
875 | + 'Show Presenter View')) |
876 | |
877 | def set_controller_text(self, checkbox, controller): |
878 | if checkbox.isEnabled(): |
879 | @@ -103,6 +112,7 @@ |
880 | checkbox = self.presenter_check_boxes[controller.name] |
881 | checkbox.setChecked(Settings().value(self.settings_section + '/' + controller.name)) |
882 | self.override_app_check_box.setChecked(Settings().value(self.settings_section + '/override app')) |
883 | + self.show_presenter_view_check_box.setChecked(Settings().value(self.settings_section + '/show presenter view')) |
884 | |
885 | def save(self): |
886 | """ |
887 | @@ -128,6 +138,10 @@ |
888 | if Settings().value(setting_key) != self.override_app_check_box.checkState(): |
889 | Settings().setValue(setting_key, self.override_app_check_box.checkState()) |
890 | changed = True |
891 | + setting_key = self.settings_section + '/show presenter view' |
892 | + if Settings().value(setting_key) != self.show_presenter_view_check_box.checkState(): |
893 | + Settings().setValue(setting_key, self.show_presenter_view_check_box.isChecked()) |
894 | + changed = True |
895 | if changed: |
896 | self.settings_form.register_post_process('mediaitem_suffix_reset') |
897 | self.settings_form.register_post_process('mediaitem_presentation_rebuild') |
898 | |
899 | === modified file 'openlp/plugins/presentations/presentationplugin.py' |
900 | --- openlp/plugins/presentations/presentationplugin.py 2013-10-13 21:07:28 +0000 |
901 | +++ openlp/plugins/presentations/presentationplugin.py 2013-10-26 22:59:24 +0000 |
902 | @@ -31,6 +31,7 @@ |
903 | formats. |
904 | """ |
905 | import os |
906 | +import sys |
907 | import logging |
908 | |
909 | from PyQt4 import QtCore |
910 | @@ -48,6 +49,11 @@ |
911 | 'presentations/Impress': QtCore.Qt.Checked, |
912 | 'presentations/Powerpoint': QtCore.Qt.Checked, |
913 | 'presentations/Powerpoint Viewer': QtCore.Qt.Checked, |
914 | + 'presentations/Keynote': QtCore.Qt.Checked, |
915 | + 'presentations/show presenter view': QtCore.Qt.Checked, |
916 | + 'PresentationModeUseSecondary': '', |
917 | + 'PresentationModeEnableFeedbackDisplay': False, |
918 | + 'PresentationModePlayWellWithOthers': False, |
919 | 'presentations/presentations files': [] |
920 | } |
921 | |
922 | @@ -125,6 +131,12 @@ |
923 | controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'presentations', 'lib') |
924 | for filename in os.listdir(controller_dir): |
925 | if filename.endswith('controller.py') and not filename == 'presentationcontroller.py': |
926 | + if not sys.platform.startswith('darwin') and filename == 'powerpointmaccontroller.py': |
927 | + continue |
928 | + if not sys.platform.startswith('darwin') and filename == 'keynotemaccontroller.py': |
929 | + continue |
930 | + if not sys.platform.startswith('win') and filename == 'powerpointcontroller.py': |
931 | + continue |
932 | path = os.path.join(controller_dir, filename) |
933 | if os.path.isfile(path): |
934 | module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0] |
935 | |
936 | === modified file 'scripts/check_dependencies.py' |
937 | --- scripts/check_dependencies.py 2013-10-03 19:56:12 +0000 |
938 | +++ scripts/check_dependencies.py 2013-10-26 22:59:24 +0000 |
939 | @@ -47,6 +47,7 @@ |
940 | nose = None |
941 | |
942 | IS_WIN = sys.platform.startswith('win') |
943 | +IS_OSX = sys.platform.startswith('darwin') |
944 | |
945 | |
946 | VERS = { |
947 | @@ -57,6 +58,8 @@ |
948 | # pyenchant 1.6 required on Windows |
949 | 'enchant': '1.6' if IS_WIN else '1.3' |
950 | } |
951 | +if IS_OSX: |
952 | + VERS.update({'appscript': '1.0.0'}) |
953 | |
954 | # pywin32 |
955 | WIN32_MODULES = [ |
956 | @@ -67,6 +70,11 @@ |
957 | 'icu', |
958 | ] |
959 | |
960 | +# OSX |
961 | +OSX_MODULES = [ |
962 | + 'appscript', |
963 | + 'mactypes', |
964 | +] |
965 | MODULES = [ |
966 | 'PyQt4', |
967 | 'PyQt4.QtCore', |
968 | @@ -177,6 +185,12 @@ |
969 | check_vers(enchant.__version__, VERS['enchant'], 'enchant') |
970 | except ImportError: |
971 | print_vers_fail(VERS['enchant'], 'enchant') |
972 | + if IS_OSX: |
973 | + try: |
974 | + import appscript |
975 | + check_vers(appscript.__version__, VERS['appscript'], 'appscript') |
976 | + except ImportError: |
977 | + print_vers_fail(VERS['appscript'], 'appscript') |
978 | |
979 | |
980 | def print_enchant_backends_and_languages(): |
981 | @@ -228,6 +242,10 @@ |
982 | print('Checking for Windows specific modules...') |
983 | for m in WIN32_MODULES: |
984 | check_module(m) |
985 | + if IS_OSX: |
986 | + print('Checking for OS X specific modules...') |
987 | + for m in OSX_MODULES: |
988 | + check_module(m) |
989 | verify_versions() |
990 | print_qt_image_formats() |
991 | print_enchant_backends_and_languages() |
992 | |
993 | === added file 'tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py' |
994 | --- tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py 1970-01-01 00:00:00 +0000 |
995 | +++ tests/functional/openlp_plugins/presentations/test_keynotemaccontroller.py 2013-10-26 22:59:24 +0000 |
996 | @@ -0,0 +1,93 @@ |
997 | +""" |
998 | +This module contains tests for the KeynoteController class of the Presentations plugin. |
999 | +""" |
1000 | + |
1001 | +from unittest import TestCase |
1002 | + |
1003 | +from tests.functional import MagicMock |
1004 | +import os |
1005 | +from openlp.plugins.presentations.lib.keynotemaccontroller import KeynoteController, KeynoteDocument |
1006 | + |
1007 | +RESOURCES_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources')) |
1008 | + |
1009 | +# TODO: write tests for classes |
1010 | +# - KeynoteController |
1011 | +# - KeynoteDocument |
1012 | + |
1013 | +class TestKeynoteController(TestCase): |
1014 | + """ |
1015 | + Test the KeynoteController class |
1016 | + """ |
1017 | + def setUp(self): |
1018 | + """ |
1019 | + Set up the KeynoteController |
1020 | + """ |
1021 | + presentation_controller = MagicMock() |
1022 | + presentation_controller.settings_section = 'presentations' |
1023 | + self.keynote_controller = KeynoteController(presentation_controller) |
1024 | + self.file_name = os.path.join(RESOURCES_PATH,'test.key') |
1025 | + self.doc = KeynoteDocument(self.keynote_controller,self.file_name) |
1026 | + self.doc.presentation_deleted() |
1027 | + |
1028 | + def kill_test(self): |
1029 | + """ |
1030 | + Test running the kill() method with an KeynoteController |
1031 | + """ |
1032 | + # GIVEN: A KeynoteController instance and a list of documents |
1033 | + presentation_controller = MagicMock() |
1034 | + presentation_controller.settings_section = 'presentations' |
1035 | + keynote_controller = KeynoteController(presentation_controller) |
1036 | + key_document = MagicMock() |
1037 | + keynote_controller.docs.append(key_document) |
1038 | + # WHEN: we run kill() |
1039 | + keynote_controller.kill() |
1040 | + # THEN: all docs should be deleted from controller |
1041 | + assert keynote_controller.docs.count() == 0, 'The keynote_controller should close all documents.' |
1042 | + assert keynote_controller.process in None, 'The keynote_controller should shout down KeyNote application.' |
1043 | + |
1044 | + def verify_installation_test(self): |
1045 | + """ |
1046 | + Test the installation of KeyNote |
1047 | + """ |
1048 | + # GIVEN: A boolean value set to true |
1049 | + # WHEN: We "convert" it to a bool |
1050 | + is_installed = self.keynote_controller.check_available() |
1051 | + # THEN: We should get back a True bool |
1052 | + assert is_installed is True, u'The result of check_available() should be True' |
1053 | + |
1054 | + def start_process_test(self): |
1055 | + """ |
1056 | + Test the start_process() of KeyNote |
1057 | + """ |
1058 | + # GIVEN: A boolean value set to true |
1059 | + # WHEN: We "convert" it to a bool |
1060 | + self.keynote_controller.start_process() |
1061 | + # THEN: The process should not be None |
1062 | + assert self.keynote_controller.process is not None, u'The result of start_process() should be True' |
1063 | + |
1064 | + def load_presentation_test(self): |
1065 | + """ |
1066 | + Test loading a document in KeyNote |
1067 | + """ |
1068 | + # GIVEN: the filename |
1069 | + self.doc = KeynoteDocument(self.keynote_controller,self.file_name) |
1070 | + # WHEN: loading the filename |
1071 | + self.doc.load_presentation() |
1072 | + result = self.doc.is_loaded() |
1073 | + # THEN: result should be true |
1074 | + assert result is True, u'The KeyNote should load document' |
1075 | + assert self.keynote_controller.docs.count() != 0, 'The keynote_controller.docs should have one document.' |
1076 | + |
1077 | + def close_presentation_test(self): |
1078 | + """ |
1079 | + Test closing a document in KeyNote |
1080 | + """ |
1081 | + # GIVEN: loading the filename |
1082 | + self.doc = KeynoteDocument(self.keynote_controller,self.file_name) |
1083 | + self.doc.load_presentation() |
1084 | + # WHEN: closing the filename |
1085 | + self.doc.close_presentation() |
1086 | + result = self.doc.is_loaded() |
1087 | + # THEN: result should be true |
1088 | + assert result is False, u'The KeyNote should close document' |
1089 | + assert self.keynote_controller.docs.count() == 0, 'The keynote_controller.docs should have 0 documents.' |
1090 | |
1091 | === added file 'tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py' |
1092 | --- tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py 1970-01-01 00:00:00 +0000 |
1093 | +++ tests/functional/openlp_plugins/presentations/test_powepointmaccontroller.py 2013-10-26 22:59:24 +0000 |
1094 | @@ -0,0 +1,93 @@ |
1095 | +""" |
1096 | +This module contains tests for the PowerpointController class of the Presentations plugin. |
1097 | +""" |
1098 | + |
1099 | +from unittest import TestCase |
1100 | + |
1101 | +from tests.functional import MagicMock |
1102 | +import os |
1103 | +from openlp.plugins.presentations.lib.powerpointmaccontroller import PowerpointController, PowerpointDocument |
1104 | + |
1105 | +RESOURCES_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources')) |
1106 | + |
1107 | +# TODO: write tests for classes |
1108 | +# - PowerpointController |
1109 | +# - PowerpointDocument |
1110 | + |
1111 | +class TestPowerpointController(TestCase): |
1112 | + """ |
1113 | + Test the PowerpointController class |
1114 | + """ |
1115 | + def setUp(self): |
1116 | + """ |
1117 | + Set up the PowerpointController |
1118 | + """ |
1119 | + presentation_controller = MagicMock() |
1120 | + presentation_controller.settings_section = 'presentations' |
1121 | + self.powerpoint_controller = PowerpointController(presentation_controller) |
1122 | + self.file_name = os.path.join(RESOURCES_PATH,'test.pptx') |
1123 | + self.doc = PowerpointDocument(self.powerpoint_controller,self.file_name) |
1124 | + self.doc.presentation_deleted() |
1125 | + |
1126 | + def kill_test(self): |
1127 | + """ |
1128 | + Test running the kill() method with an PowerpointController |
1129 | + """ |
1130 | + # GIVEN: A PowerpointController instance and a list of documents |
1131 | + presentation_controller = MagicMock() |
1132 | + presentation_controller.settings_section = 'presentations' |
1133 | + powerpoint_controller = PowerpointController(presentation_controller) |
1134 | + ppt_document = MagicMock() |
1135 | + powerpoint_controller.docs.append(ppt_document) |
1136 | + # WHEN: we run kill() |
1137 | + powerpoint_controller.kill() |
1138 | + # THEN: all docs should be deleted from controller |
1139 | + assert powerpoint_controller.docs.count() == 0, 'The powerpoint_controller should close all documents.' |
1140 | + assert powerpoint_controller.process in None, 'The powerpoint_controller should shout down PPT application.' |
1141 | + |
1142 | + def verify_installation_test(self): |
1143 | + """ |
1144 | + Test the installation of PPT |
1145 | + """ |
1146 | + # GIVEN: A boolean value set to true |
1147 | + # WHEN: We "convert" it to a bool |
1148 | + is_installed = self.powerpoint_controller.check_available() |
1149 | + # THEN: We should get back a True bool |
1150 | + assert is_installed is True, u'The result of check_available() should be True' |
1151 | + |
1152 | + def start_process_test(self): |
1153 | + """ |
1154 | + Test the start_process() of PPT |
1155 | + """ |
1156 | + # GIVEN: A boolean value set to true |
1157 | + # WHEN: We "convert" it to a bool |
1158 | + self.powerpoint_controller.start_process() |
1159 | + # THEN: The process should not be None |
1160 | + assert self.powerpoint_controller.process is not None, u'The result of start_process() should be True' |
1161 | + |
1162 | + def load_presentation_test(self): |
1163 | + """ |
1164 | + Test loading a document in PPT |
1165 | + """ |
1166 | + # GIVEN: the filename |
1167 | + self.doc = PowerpointDocument(self.powerpoint_controller,self.file_name) |
1168 | + # WHEN: loading the filename |
1169 | + self.doc.load_presentation() |
1170 | + result = self.doc.is_loaded() |
1171 | + # THEN: result should be true |
1172 | + assert result is True, u'The PPT should load document' |
1173 | + assert self.powerpoint_controller.docs.count() != 0, 'The powerpoint_controller.docs should have one document.' |
1174 | + |
1175 | + def close_presentation_test(self): |
1176 | + """ |
1177 | + Test closing a document in PPT |
1178 | + """ |
1179 | + # GIVEN: loading the filename |
1180 | + self.doc = PowerpointDocument(self.powerpoint_controller,self.file_name) |
1181 | + self.doc.load_presentation() |
1182 | + # WHEN: closing the filename |
1183 | + self.doc.close_presentation() |
1184 | + result = self.doc.is_loaded() |
1185 | + # THEN: result should be true |
1186 | + assert result is False, u'The PPT should close document' |
1187 | + assert self.powerpoint_controller.docs.count() == 0, 'The powerpoint_controller.docs should have 0 documents.' |
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