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

Proposed by Dmitriy Marmyshev
Status: Superseded
Proposed branch: lp:~marmyshev/openlp/presentation
Merge into: lp:openlp
Diff against target: 1182 lines (+996/-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 (+362/-0)
openlp/plugins/presentations/lib/powerpointmaccontroller.py (+399/-0)
openlp/plugins/presentations/lib/presentationtab.py (+12/-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
matysek (community) Approve
Tim Bentley Pending
Dmitriy Marmyshev Pending
Andreas Preikschat Pending
Raoul Snyman Pending
Review via email: mp+185973@code.launchpad.net

This proposal supersedes a proposal from 2013-04-06.

This proposal has been superseded by 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 :

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

Revision history for this message
Dmitriy Marmyshev (marmyshev) wrote :

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 :
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 :
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 :

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 :

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 :

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 :

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 :

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 :

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 :

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 :

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 :

> 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?

lp:~marmyshev/openlp/presentation updated
2138. By Dmitriy Marmyshev

Tests

2139. By Dmitriy Marmyshev

Added check_ver for appscript module

2140. By Dmitriy Marmyshev

Trunk

2141. By Dmitriy Marmyshev

cleanups.

2142. By Dmitriy Marmyshev

Trunk

2143. By Dmitriy Marmyshev

tests fixes

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-24 16:44:10 +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-24 16:44:10 +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-24 16:44:10 +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-24 16:44:10 +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-24 16:44:10 +0000
@@ -0,0 +1,362 @@
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
31#import sys
32import logging
33#import mactypes
34
35import appscript
36
37from openlp.core.lib import Settings, ScreenList
38from .presentationcontroller import PresentationController, PresentationDocument
39
40
41log = logging.getLogger(__name__)
42
43
44class KeynoteController(PresentationController):
45 """
46 Class to control interactions with KeyNote 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('KeynoteController loaded')
51
52 def __init__(self, plugin):
53 """
54 Initialise the class
55 """
56 log.debug('Initialising')
57 super(KeynoteController, self).__init__(plugin, 'Keynote', KeynoteDocument)
58 self.supports = ['key']
59 self.process = None
60
61 def check_available(self):
62 """
63 KeyNote is able to run on this machine
64 """
65 log.debug('check_available')
66 try:
67 self.process = appscript.app('Keynote')
68 except appscript.ApplicationNotFoundError:
69 return False
70 self.kill()
71 return True
72
73 def start_process(self):
74 """
75 Loads KeyNote process
76 """
77 log.debug('start_process')
78 if not self.process or not self.process.isrunning():
79 self.process = appscript.app('Keynote')
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 Keynote')
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.slideshows()
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 Keynote
105 PresentationModeEnableFeedbackDisplay = True if in settings of OpenLP show presenter view = True
106 PresentationModeUseSecondary = 1 if OpenLP monitor for output = Screen 2
107 """
108 openlp_settings = Settings('openlp.org','OpenLP')
109 keynote_settings = Settings('apple', 'iWork.Keynote')
110 use_secondary = int(keynote_settings.value('PresentationModeUseSecondary'))
111 monitor = openlp_settings.value( 'core/monitor')
112 override_position = openlp_settings.value( 'core/override position')
113 if not override_position and use_secondary != monitor:
114 keynote_settings.setValue('PresentationModeUseSecondary', monitor)
115 elif override_position and use_secondary != 0:
116 keynote_settings.setValue('PresentationModeUseSecondary', '0')
117 show_presenter_view = openlp_settings.value(self.plugin.settings_section + '/show presenter view')
118 keynote_feedback_display = keynote_settings.value('PresentationModeEnableFeedbackDisplay')
119 if show_presenter_view != keynote_feedback_display:
120 keynote_settings.setValue('PresentationModeEnableFeedbackDisplay', show_presenter_view)
121 play_well_with_others = keynote_settings.value('PresentationModePlayWellWithOthers')
122 if not play_well_with_others:
123 keynote_settings.setValue('PresentationModePlayWellWithOthers', True)
124
125
126class KeynoteDocument(PresentationDocument):
127 """
128 Class which holds information and controls a single presentation
129 """
130
131 def __init__(self, controller, presentation):
132 """
133 Constructor, store information about the file and initialise
134 """
135 log.debug('Init Presentation Keynote')
136 super(KeynoteDocument, self).__init__(controller, presentation)
137 self.presentation = None
138
139 def load_presentation(self):
140 """
141 Called when a presentation is added to the SlideController.
142 Opens the Keynote file using the process created earlier.
143 """
144 log.debug('load_presentation')
145 if not self.controller.process or not self.controller.process.isrunning():
146 self.controller.start_process()
147 try:
148 self.controller.process.open(self.filepath)
149 except appscript.CommandError:
150 log.debug('Keynote open failed')
151 return False
152 slideshows = self.controller.process.slideshows()
153 for slideshow in slideshows:
154 path = slideshow.path()
155 if self.filepath == path:
156 self.presentation = slideshow
157 self.create_thumbnails()
158 return True
159 self.presentation = None
160 return False
161
162 def create_thumbnails(self):
163 """
164 Create the thumbnail images for the current presentation.
165 """
166 log.debug('create_thumbnails')
167 if self.check_thumbnails():
168 return
169 thumbnail_folder = self.get_thumbnail_folder()
170 if not os.path.exists(thumbnail_folder):
171 os.makedirs(thumbnail_folder)
172 try:
173 self.controller.process.open(self.filepath)
174 except appscript.CommandError:
175 log.debug('KeyNote open failed')
176 return
177 temp_dir = self.controller.thumbnail_folder
178 keystroke = os.path.join(temp_dir, 'temp' + self.controller.thumbnail_prefix)
179 self.controller.process.activate()
180 appscript.app('System Events').processes['Keynote'].menu_bars[1].menu_bar_items[3].menus.menu_items[11].click()
181 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].tool_bars.buttons[4].click()
182 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].radio_groups[1].radio_buttons[1].click()
183 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].pop_up_buttons[1].click()
184 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].pop_up_buttons[1]\
185 .menus.menu_items[2].click()
186 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].buttons[2].click()
187 appscript.app('System Events').processes['Keynote'].keystroke(keystroke)
188 appscript.app('System Events').processes['Keynote'].key_code(36)
189 appscript.app('System Events').processes['Keynote'].windows[1].sheets[1].buttons[1].click()
190 self.controller.plugin._main_window.activateWindow()
191 slide_no = 0
192 for filename in os.listdir(temp_dir):
193 full_filename = os.path.join(temp_dir, filename)
194 if not os.path.isfile(full_filename) or not filename.endswith('.png') or filename == 'icon.png':
195 continue
196 slide_no = slide_no + 1
197 if not filename.startswith(self.controller.thumbnail_prefix):
198 path = os.path.join(thumbnail_folder,
199 self.controller.thumbnail_prefix + str(slide_no) + '.png')
200 try:
201 os.rename(full_filename, path)
202 except:
203 open(path,'w').write(open(full_filename,'r').read())
204 os.unlink(full_filename)
205
206 def close_presentation(self):
207 """
208 Close presentation and clean up objects. This is triggered by a new
209 object being added to SlideController or OpenLP being shut down.
210 """
211 log.debug('close_presentation')
212 if self.presentation:
213 try:
214 self.presentation.close()
215 except appscript.CommandError:
216 log.debug('Could not close the presentation')
217 self.presentation = None
218 self.controller.remove_doc(self)
219
220 def is_loaded(self):
221 """
222 Returns ``True`` if a presentation is loaded.
223 """
224 log.debug('is_loaded')
225 try:
226 if not self.controller.process.isrunning():
227 return False
228 windows = self.controller.process.windows()
229 if len(windows) == 0:
230 return False
231 slideshows = self.controller.process.slideshows()
232 if len(slideshows) == 0:
233 return False
234 except:
235 return False
236 for slideshow in slideshows:
237 path = slideshow.path()
238 if self.filepath == path:
239 return True
240 return False
241
242 def is_active(self):
243 """
244 Returns ``True`` if a presentation is currently active.
245 """
246 log.debug('is_active')
247 if not self.is_loaded():
248 return False
249 try:
250 if not self.presentation.playing():
251 return False
252 except appscript.CommandError:
253 return False
254 return True
255
256 def unblank_screen(self):
257 """
258 Unblanks (restores) the presentation.
259 """
260 log.debug('unblank_screen')
261 if self.is_blank():
262 self.presentation.start_presentation()
263
264 def blank_screen(self):
265 """
266 Blanks the screen.
267 """
268 log.debug('blank_screen')
269 self.presentation.stop_slideshow()
270
271 def is_blank(self):
272 """
273 Returns ``True`` if screen is blank.
274 """
275 log.debug('is_blank')
276 if self.is_active():
277 return not self.presentation.playing()
278 else:
279 return False
280
281 def stop_presentation(self):
282 """
283 Stops the current presentation and hides the output.
284 """
285 log.debug('stop_presentation')
286 self.presentation.stop_slideshow()
287
288
289 def start_presentation(self):
290 """
291 Starts a presentation from the beginning.
292 """
293 log.debug('start_presentation')
294 if not self.is_active():
295 self.controller.apply_app_settings()
296 try:
297 self.presentation.start()
298 except appscript.CommandError:
299 return
300 rect = ScreenList().current['size']
301 top = rect.y()
302 height = rect.height()
303 left_position = rect.x()
304 width = rect.width()
305 self.controller.process.windows[1].bounds.set([left_position, top, left_position + width, top + height])
306
307 def get_slide_number(self):
308 """
309 Returns the current slide number.
310 """
311 log.debug('get_slide_number')
312 return self.presentation.current_slide().slide_number()
313
314 def get_slide_count(self):
315 """
316 Returns total number of slides.
317 """
318 log.debug('get_slide_count')
319 slides = self.presentation.slides()
320 return len(slides)
321
322 def goto_slide(self, slideno):
323 """
324 Moves to a specific slide in the presentation.
325 """
326 log.debug('goto_slide')
327 slide = self.presentation.slides()[slideno-1]
328 self.presentation.show(slide)
329
330 def next_step(self):
331 """
332 Triggers the next effect of slide on the running presentation.
333 """
334 log.debug('next_step')
335 self.presentation.show_next()
336 if self.get_slide_number() > self.get_slide_count():
337 self.previous_step()
338
339 def previous_step(self):
340 """
341 Triggers the previous slide on the running presentation.
342 """
343 log.debug('previous_step')
344 self.presentation.show_previous()
345
346 def get_slide_text(self, slide_no):
347 """
348 Returns the text on the slide.
349
350 ``slide_no``
351 The slide the text is required for, starting at 1.
352 """
353 return self.presentation.slides[slide_no].body
354
355 def get_slide_notes(self, slide_no):
356 """
357 Returns the text on the slide.
358
359 ``slide_no``
360 The slide the notes are required for, starting at 1.
361 """
362 return self.presentation.slides[slide_no].notes
0363
=== 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-24 16:44:10 +0000
@@ -0,0 +1,399 @@
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 sys
32import logging
33import shutil
34#import mactypes
35
36import appscript
37
38from openlp.core.lib import Settings, ScreenList
39from .presentationcontroller import PresentationController, PresentationDocument
40
41
42log = logging.getLogger(__name__)
43
44
45class PowerpointController(PresentationController):
46 """
47 Class to control interactions with PowerPoint Presentations
48 It creates the runtime Environment , Loads the and Closes the Presentation
49 As well as triggering the correct activities based on the users input
50 """
51 log.info(u'PowerpointController loaded')
52
53 def __init__(self, plugin):
54 """
55 Initialise the class
56 """
57 log.debug('Initialising')
58 super(PowerpointController, self).__init__(plugin, 'Powerpoint', PowerpointDocument)
59 self.supports = ['ppt', 'pps', 'pptx', 'ppsx']
60 self.process = None
61
62 def check_available(self):
63 """
64 PowerPoint is able to run on this machine
65 """
66 log.debug('check_available')
67 try:
68 self.process = appscript.app(id='com.microsoft.powerpoint')
69 except appscript.ApplicationNotFoundError:
70 return False
71 self.kill()
72 return True
73
74 def start_process(self):
75 """
76 Loads PowerPoint process
77 """
78 log.debug('start_process')
79 if not self.process or not self.process.isrunning():
80 self.process = appscript.app(id='com.microsoft.powerpoint')
81 self.process.relaunchmode = 'limited' #'always'
82 self.process.launch()
83 self.apply_app_settings()
84
85 def kill(self):
86 """
87 Called at system exit to clean up any running presentations
88 """
89 log.debug('Kill Powerpoint')
90 while self.docs and self.process.isrunning():
91 self.docs[0].close_presentation()
92 if self.process is None or not self.process.isrunning():
93 return
94 try:
95 total = self.process.presentations()
96 if self.process and total != appscript.k.missing_value and len(total) > 0:
97 return
98 self.process.quit(saving = appscript.k.ask)
99 except appscript.CantLaunchApplicationError:
100 log.debug('Kill Keynote failed')
101 self.process = None
102
103 def apply_app_settings(self):
104 """
105 Apply settings for PowerPoint
106 14\Options\Options\Save graphics screen heigth = 240
107 14\Options\Options\Save graphics screen width = 320
108 14\Options\Options\Save only current slide graphics = 0
109
110 """
111 #TODO: add settings for different versions of MS PPT
112 pass
113
114
115class PowerpointDocument(PresentationDocument):
116 """
117 Class which holds information and controls a single presentation
118 """
119
120 def __init__(self, controller, presentation):
121 """
122 Constructor, store information about the file and initialise
123 """
124 log.debug('Init Presentation Powerpoint')
125 super(PowerpointDocument, self).__init__(controller, presentation)
126 self.presentation = None
127
128 def load_presentation(self):
129 """
130 Called when a presentation is added to the SlideController.
131 Opens the PowerPoint file using the process created earlier.
132 """
133 log.debug('load_presentation')
134 if not self.controller.process or not self.controller.process.isrunning():
135 self.controller.start_process()
136 try:
137 self.controller.process.open(self.filepath)
138 except appscript.CommandError:
139 log.debug('PPT open failed')
140 return False
141 presentations = self.controller.process.presentations()
142 for presentation in presentations:
143 full_name = presentation.full_name()
144 full_name = full_name.replace('Macintosh HD', '')
145 full_name = full_name.replace(':', '/')
146 if self.filepath == full_name:
147 self.presentation = presentation
148 self.create_thumbnails()
149 return True
150 return False
151
152 def create_thumbnails(self):
153 """
154 Create the thumbnail images for the current presentation.
155 """
156 log.debug('create_thumbnails')
157 if self.check_thumbnails():
158 return
159 thumbnail_folder = self.get_thumbnail_folder()
160 self.presentation.save(in_=thumbnail_folder, as_=appscript.k.save_as_PNG)
161 slide_no = 0
162 self.move_thumbnails(thumbnail_folder, slide_no, thumbnail_folder)
163
164 def move_thumbnails(self, thumbnail_folder, slide_no, temp_dir):
165 """
166 Move the thumbnail images from subdirectories to right path.
167 """
168 if not os.path.isdir(temp_dir):
169 return
170 for filename in os.listdir(temp_dir):
171 full_filename = os.path.join(temp_dir, filename)
172 if os.path.isdir(full_filename):
173 self.move_thumbnails(thumbnail_folder, slide_no, full_filename)
174 elif os.path.isfile(full_filename) and filename.endswith('.png') and not filename == 'icon.png':
175 slide_no = slide_no + 1
176 new_name = os.path.join(thumbnail_folder, self.controller.thumbnail_prefix + str(slide_no) + '.png')
177 if full_filename == new_name \
178 or full_filename.startswith(os.path.join(thumbnail_folder, self.controller.thumbnail_prefix)):
179 continue
180 try:
181 os.rename(full_filename, new_name)
182 except:
183 open(new_name,'w').write(open(full_filename,'r').read())
184 os.unlink(full_filename)
185 if temp_dir != thumbnail_folder:
186 try:
187 shutil.rmtree(temp_dir)
188 except:
189 pass
190
191 def close_presentation(self):
192 """
193 Close presentation and clean up objects. This is triggered by a new
194 object being added to SlideController or OpenLP being shut down.
195 """
196 log.debug('close_presentation')
197 if self.presentation:
198 try:
199 self.presentation.close()
200 except appscript.CommandError:
201 log.debug('Could not close the presentation')
202 self.presentation = None
203 self.controller.remove_doc(self)
204
205 def is_loaded(self):
206 """
207 Returns ``True`` if a presentation is loaded.
208 """
209 log.debug('is_loaded')
210 try:
211 if not self.controller.process.isrunning():
212 return False
213 if len(self.controller.process.document_windows()) == 0:
214 return False
215 presentations = self.controller.process.presentations()
216 if len(presentations) == 0:
217 return False
218 except:
219 return False
220 for presentation in presentations:
221 full_name = presentation.full_name()
222 full_name = full_name.replace('Macintosh HD', '')
223 full_name = full_name.replace(':', '/')
224 if self.filepath == full_name:
225 return True
226 return False
227
228 def is_active(self):
229 """
230 Returns ``True`` if a presentation is currently active.
231 """
232 log.debug('is_active')
233 if not self.is_loaded():
234 return False
235 try:
236 slide_show_window = self.presentation.slide_show_window
237 if slide_show_window is None:
238 return False
239 slide_state = self.presentation.slide_show_window.slideshow_view.slide_state()
240 if slide_state is None or slide_state == appscript.k.missing_value:
241 return False
242 except:
243 return False
244 return True
245
246 def unblank_screen(self):
247 """
248 Unblanks (restores) the presentation.
249 """
250 log.debug('unblank_screen')
251 if self.is_blank():
252 settings = self.presentation.slide_show_settings
253 self.presentation.slide_show_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_running)
254 self.presentation.slide_show_window.slideshow_view.go_to_next_slide()
255 self.presentation.slide_show_window.slideshow_view.go_to_previous_slide()
256
257 def blank_screen(self):
258 """
259 Blanks the screen.
260 """
261 log.debug('blank_screen')
262 self.presentation.slide_show_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_black_screen)
263
264 def is_blank(self):
265 """
266 Returns ``True`` if screen is blank.
267 """
268 log.debug('is_blank')
269 if self.is_active() and self.presentation.slide_show_window.slideshow_view\
270 .slide_state() is appscript.k.slide_show_state_black_screen:
271 return True
272 else:
273 return False
274
275 def stop_presentation(self):
276 """
277 Stops the current presentation and hides the output.
278 """
279 log.debug('stop_presentation')
280 self.presentation.slide_show_window.slideshow_view.exit_slide_show()
281
282
283 def start_presentation(self):
284 """
285 Starts a presentation from the beginning.
286 """
287 log.debug('start_presentation')
288 rect = ScreenList().current['size']
289 ppt_settings = self.presentation.slide_show_settings
290 openlp_settings = Settings("openlp.org","OpenLP")
291 show_presenter_view = openlp_settings.value(self.controller.plugin.settings_section + '/show presenter view')
292 override_position = openlp_settings.value( 'general/override position')
293 if show_presenter_view:
294 ppt_settings.show_type.set(appscript.k.slide_show_type_presenter)
295 elif override_position:
296 ppt_settings.show_type.set(appscript.k.slide_show_type_window)
297 else:
298 ppt_settings.show_type.set(appscript.k.slide_show_type_kiosk)
299 #ppt_settings.show_type.set(appscript.k.slide_show_type_speaker)
300 ppt_window = ppt_settings.run_slide_show()
301 #TODO: set slideshow state = running
302# if ppt_window.slideshow_view.slide_state() != appscript.k.slide_show_state_running:
303# ppt_window.slideshow_view.slide_state.set(appscript.k.slide_show_state_running)
304 if not ppt_window or show_presenter_view:
305 return
306 if override_position:
307 top = float(rect.y())
308 height = float(rect.height())
309 left_position = float(rect.x())
310 width = float(rect.width())
311 ppt_window.top.set(top)
312 ppt_window.height.set(height)
313 ppt_window.left_position.set(left_position)
314 ppt_window.width.set(width)
315 else:
316 #TODO: set output monitor for fullscreen mode
317 pass
318
319 def get_slide_number(self):
320 """
321 Returns the current slide number.
322 """
323 log.debug('get_slide_number')
324 return self.presentation.slide_show_window.slideshow_view.current_show_position()
325
326 def get_slide_count(self):
327 """
328 Returns total number of slides.
329 """
330 log.debug('get_slide_count')
331 return len(self.presentation.slides())
332
333 def goto_slide(self, slideno):
334 """
335 Moves to a specific slide in the presentation.
336 """
337 log.debug('goto_slide')
338 #FIXME: this works. but needs to fix this dumb code
339 while self.get_slide_number() != slideno:
340 if self.get_slide_number() < slideno:
341 self.presentation.slide_show_window.slideshow_view.go_to_next_slide()
342 else:
343 self.presentation.slide_show_window.slideshow_view.go_to_previous_slide()
344 self.controller.process.activate()
345
346 def next_step(self):
347 """
348 Triggers the next effect of slide on the running presentation.
349 """
350 log.debug('next_step')
351 #TODO: check if slideshow stoped then restart it from current position
352 if self.is_active():
353 self.presentation.slide_show_window.slideshow_view.go_to_next_slide()
354 self.controller.process.activate()
355 if self.get_slide_number() > self.get_slide_count():
356 self.previous_step()
357
358 def previous_step(self):
359 """
360 Triggers the previous slide on the running presentation.
361 """
362 log.debug('previous_step')
363 #TODO: check if slideshow stoped then restart it from current position
364 if self.is_active():
365 self.presentation.slide_show_window.slideshow_view.go_to_previous_slide()
366 self.controller.process.activate()
367
368 def get_slide_text(self, slide_no):
369 """
370 Returns the text on the slide.
371
372 ``slide_no``
373 The slide the text is required for, starting at 1.
374 """
375 return _get_text_from_shapes(self.presentation.slides[slide_no-1].shapes)
376
377 def get_slide_notes(self, slide_no):
378 """
379 Returns the text on the slide.
380
381 ``slide_no``
382 The slide the notes are required for, starting at 1.
383 """
384 return _get_text_from_shapes(
385 self.presentation.slides[slide_no].notes_page.shapes())
386
387def _get_text_from_shapes(shapes):
388 """
389 Returns any text extracted from the shapes on a presentation slide.
390
391 ``shapes``
392 A set of shapes to search for text.
393 """
394 text = ''
395 for idx in range(len(shapes)):
396 shape = shapes[idx + 1]
397 if shape.has_text_frame():
398 text += shape.text_frame.text_range.content() + '\n'
399 return text
0400
=== 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-24 16:44:10 +0000
@@ -71,6 +71,11 @@
71 self.override_app_check_box = QtGui.QCheckBox(self.advanced_group_box)71 self.override_app_check_box = QtGui.QCheckBox(self.advanced_group_box)
72 self.override_app_check_box.setObjectName('override_app_check_box')72 self.override_app_check_box.setObjectName('override_app_check_box')
73 self.advanced_layout.addWidget(self.override_app_check_box)73 self.advanced_layout.addWidget(self.override_app_check_box)
74 self.show_presenter_view_check_box = QtGui.QCheckBox(self.advanced_group_box)
75 self.show_presenter_view_check_box.setObjectName(u'show_presenter_view_check_box')
76 self.advanced_layout.addWidget(self.show_presenter_view_check_box)
77 if not sys.platform.startswith('darwin'):
78 self.show_presenter_view_check_box.setVisible(False)
74 self.left_layout.addWidget(self.advanced_group_box)79 self.left_layout.addWidget(self.advanced_group_box)
75 self.left_layout.addStretch()80 self.left_layout.addStretch()
76 self.right_layout.addStretch()81 self.right_layout.addStretch()
@@ -87,6 +92,8 @@
87 self.advanced_group_box.setTitle(UiStrings().Advanced)92 self.advanced_group_box.setTitle(UiStrings().Advanced)
88 self.override_app_check_box.setText(93 self.override_app_check_box.setText(
89 translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden'))94 translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden'))
95 self.show_presenter_view_check_box.setText(translate('PresentationPlugin.PresentationTab',
96 'Show Presenter View'))
9097
91 def set_controller_text(self, checkbox, controller):98 def set_controller_text(self, checkbox, controller):
92 if checkbox.isEnabled():99 if checkbox.isEnabled():
@@ -103,6 +110,7 @@
103 checkbox = self.presenter_check_boxes[controller.name]110 checkbox = self.presenter_check_boxes[controller.name]
104 checkbox.setChecked(Settings().value(self.settings_section + '/' + controller.name))111 checkbox.setChecked(Settings().value(self.settings_section + '/' + controller.name))
105 self.override_app_check_box.setChecked(Settings().value(self.settings_section + '/override app'))112 self.override_app_check_box.setChecked(Settings().value(self.settings_section + '/override app'))
113 self.show_presenter_view_check_box.setChecked(Settings().value(self.settings_section + '/show presenter view'))
106114
107 def save(self):115 def save(self):
108 """116 """
@@ -128,6 +136,10 @@
128 if Settings().value(setting_key) != self.override_app_check_box.checkState():136 if Settings().value(setting_key) != self.override_app_check_box.checkState():
129 Settings().setValue(setting_key, self.override_app_check_box.checkState())137 Settings().setValue(setting_key, self.override_app_check_box.checkState())
130 changed = True138 changed = True
139 setting_key = self.settings_section + '/show presenter view'
140 if Settings().value(setting_key) != self.show_presenter_view_check_box.checkState():
141 Settings().setValue(setting_key, self.show_presenter_view_check_box.isChecked())
142 changed = True
131 if changed:143 if changed:
132 self.settings_form.register_post_process('mediaitem_suffix_reset')144 self.settings_form.register_post_process('mediaitem_suffix_reset')
133 self.settings_form.register_post_process('mediaitem_presentation_rebuild')145 self.settings_form.register_post_process('mediaitem_presentation_rebuild')
134146
=== 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-24 16:44:10 +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-24 16:44:10 +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-24 16:44:10 +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 mock 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-24 16:44:10 +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 mock 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.'