diff --git a/MANIFEST.in b/MANIFEST.in index 992685bcf..35e83e30f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,13 +4,11 @@ recursive-include openlp *.csv recursive-include openlp *.html recursive-include openlp *.js recursive-include openlp *.css -recursive-include openlp *.qm +recursive-include openlp *.png recursive-include documentation * -recursive-include resources/forms * -recursive-include resources/i18n * -recursive-include resources/images * -recursive-include scripts *.py -include resources/*.desktop +recursive-include resources * +recursive-include scripts * include copyright.txt include LICENSE +include README.txt include openlp/.version diff --git a/copyright.txt b/copyright.txt index 0e405e6e9..0ef481f2b 100644 --- a/copyright.txt +++ b/copyright.txt @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/documentation/api/source/plugins/remotes.rst b/documentation/api/source/plugins/remotes.rst index 0bcd37119..0bb05b8b9 100644 --- a/documentation/api/source/plugins/remotes.rst +++ b/documentation/api/source/plugins/remotes.rst @@ -17,3 +17,9 @@ Helper Classes & Functions .. automodule:: openlp.plugins.remotes.lib :members: + +.. autoclass:: openlp.plugins.remotes.lib.httpserver.HttpConnection + :members: + +.. autoclass:: openlp.plugins.remotes.lib.httpserver.HttpResponse + :members: diff --git a/documentation/manual/source/bibles.rst b/documentation/manual/source/bibles.rst new file mode 100644 index 000000000..41b3933aa --- /dev/null +++ b/documentation/manual/source/bibles.rst @@ -0,0 +1,180 @@ +====== +Bibles +====== + +Managing Bibles in OpenLP is a relatively simple process. There are also +converters provided to get data from other formats into OpenLP. + +Bible Importer +============== + +If you are using an earlier version of OpenLP or, come from another software +package, you may be able to convert your existing database to work in OpenLP +2.0. To access the Bible Importer :menuselection:`File --> Import --> Bible`. +You may also enter the Bible Importer by clicking the :guilabel:`Import Icon:` + +.. image:: pics/themeimportexport.png + +You will see the Bible Importer window, click :guilabel:`Next`. + +.. image:: pics/bibleimport01.png + +After clicking :guilabel:`Next` you can select from the various types of +software that OpenLP will convert Bibles from. + +.. image:: pics/bibleimport02.png + +Click on the file folder icon to choose the file of the Bible database you +want to import. See the following sections for information on the different +formats that OpenLP will import. + +Importing from OpenLP Version 1 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Converting from OpenLP Version 1 is a simple process. First you will need to +locate your Version 1 Bibles. + +Windows XP:: + + C:\Documents and Settings\All Users\Application Data\openlp.org\Data\Bibles\ + +Windows Vista / Windows 7:: + + C:\ProgramData\openlp.org\Data\Bibles\ + +OpenLP Version 1 Bibles have the `.bible` file extension. After selecting +all of the OpenLP Version 1 Bibles you want to convert, click :guilabel:`Next` + +.. image:: pics/bibleimportdetails1.png + +Enter your Bible name and copyright details. Click :guilabel:`Next`. It may +take some time to convert your Bibles so please be patient. + +.. image:: pics/bibleimportfinished1.png + +When the import has finished click :guilabel:`Finish` and you should be +ready to use your OpenLP Version 1 Bibles. + +Importing OSIS Bibles +^^^^^^^^^^^^^^^^^^^^^ + +**About OSIS Formatted Bibles** + +OSIS is a format intended to provide a common format for Bibles. More +information can be found out here: http://www.bibletechnologies.net/ + +If you have any software installed that is part of the Sword Project +http://www.crosswire.org/sword/index.jsp it can be easily converted. + +Importing OSIS files is very simple. Select your OSIS Bible file and click +:guilabel:`Next` + +.. image:: pics/bibleimportdetails1.png + +Enter you Bible name and copyright details. Click :guilabel:`Next`. It may take +some time to convert your Bibles so please be patient. + +.. image:: pics/bibleimportfinished1.png + +Click :guilabel:`Finish` and you should be ready to use your OpenLP Version +1 Bibles. + +You can use the commands below convert Bibles from that software to OSIS format. + +The following commands are used in all platforms and the commands are case +sensitive across all platforms. To convert a Bible using Command Prompt in +Windows or a Terminal in Linux or MAC you would type:: + + mod2osis biblename > biblename.osis + +For example: if I wanted to convert a King James Version Bible I would type +something similar to this:: + + mod2osis KJV > kjv.osis + +You may also wish to dictate a file location for the conversion to place the +osis file for example:: + + mod2osis KJV > /home/user/bibles/kjv.osis + +Importing OpenSong Bibles +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Converting from OpenSong you will need to locate your bibles database. In the +later versions of OpenSong you are asked to define the location of this. The +songs will be located in a folder named :guilabel:`Bibles`. This folder should +contain files with all your bibles in them without a file extension. (file.xmms). +When you have located this folder you will need to select the bible from the +folder. + +You may also import downloaded bibles from OpenSong. The process is the same, +except you will need to extract the bible from a zip file. This is usually done +by right clicking on the downloaded file and select `Extract` or `Extract Here`. + +After selecting the OpenSong Bibles you want to convert, click :guilabel:`Next` + +.. image:: pics/bibleimportdetails1.png + +Enter your Bible name and copyright details. Click :guilabel:`Next`. It may +take some time to convert your Bibles so please be patient. + +.. image:: pics/bibleimportfinished1.png + +When the import has finished then click :guilabel:`Finish` and you should now be +ready to use your OpenSong Bibles. + +Importing Web Download Bibles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**About Web Download** + +OpenLP provides a Web Download method to import Bibles when you do not have a +locally installed Bible available. The Web Download method registers the Bible +in OpenLP like the other bibles only it downloads the verses as you need them. +This import is not meant to be used as your sole source for Bibles, but rather +as another option and does require an internet connection. + +To use the web download feature select web download from the import wizard. + +.. image:: pics/bibleimport01.png + +You can select from several options of location to download from and also +what Bible translation you need. You will probably want to choose the location +from where you get the best performance or has the translation you need. + +.. image:: pics/webbible1.png + +You can also select a proxy server if needed from the `Proxy Server` tab. Your +network administrator will know if this is necessary, in most cases this will +not be needed. + +.. image:: pics/webbibleproxy1.png + +After selecting your download location and the Bible you wish to use, click +:guilabel:`Next` When your import is completed click :guilabel:`Finish` + +.. image:: pics/biblewebcomplete.png + +You should now be ready to use the web bible. + +Importing CSV formatted Bibles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have a Bible in .csv format OpenLP can import it. CSV Bibles will +consist of two files a `books` file and a `verse` file. + +Select CSV from the list of Bible types to import. + +.. image:: pics/bibleimport02.png + +You are now ready to select your .csv files. You will need to select both your +books and verse file location. + +.. image:: pics/csvimport1.png + +After you have selected the file locations you can click :guilabel:`Next` + +.. image:: pics/bibleimportfinished1.png + +Click :guilabel:`Finish` and you should now be ready to use your imported CSV +Bible \ No newline at end of file diff --git a/documentation/manual/source/conf.py b/documentation/manual/source/conf.py index f0d918c11..6e9285aed 100644 --- a/documentation/manual/source/conf.py +++ b/documentation/manual/source/conf.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # OpenLP documentation build configuration file, created by -# sphinx-quickstart on Fri Jul 10 17:20:40 2009. +# sphinx-quickstart on Thu Sep 30 21:24:54 2010. # # This file is execfile()d with the current directory set to its containing dir. # @@ -11,19 +11,22 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import os import sys +import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath(os.path.join('..', '..'))) +#sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -#extensions = ['sphinx.ext.autodoc'] +extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -32,14 +35,14 @@ templates_path = ['_templates'] source_suffix = '.rst' # The encoding of source files. -source_encoding = 'utf-8' +#source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'OpenLP' -copyright = u'2004-2010 Raoul Snyman' +copyright = u'2010, Raoul Snyman' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -48,7 +51,7 @@ copyright = u'2004-2010 Raoul Snyman' # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '1.9.5' +release = '2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -60,12 +63,9 @@ release = '1.9.5' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' -# List of documents that shouldn't be included in the build. -#unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = [] +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None @@ -75,7 +75,7 @@ exclude_trees = [] # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -add_module_names = False +#add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. @@ -90,42 +90,33 @@ pygments_style = 'sphinx' # -- Options for HTML output --------------------------------------------------- -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -#html_theme = 'openlp_qthelp' +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -if html_theme == 'default': - html_theme_options = { - 'sidebarbgcolor': '#3a60a9', - 'relbarbgcolor': '#203b6f', - 'footerbgcolor': '#26437c', - 'headtextcolor': '#203b6f', - 'linkcolor': '#26437c', - 'sidebarlinkcolor': '#ceceff' - } +#html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = [u'../themes'] +#html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = u'OpenLP 2.0 User Manual' +#html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = 'pics/logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = 'pics/openlp.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -148,7 +139,7 @@ html_static_path = ['_static'] #html_additional_pages = {} # If false, no module index is generated. -#html_use_modindex = True +#html_domain_indices = True # If false, no index is generated. #html_use_index = True @@ -159,16 +150,22 @@ html_static_path = ['_static'] # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'OpenLP-2.0-manual' +htmlhelp_basename = 'OpenLPdoc' # -- Options for LaTeX output -------------------------------------------------- @@ -182,8 +179,8 @@ htmlhelp_basename = 'OpenLP-2.0-manual' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'OpenLP.tex', u'OpenLP 2.0 User Manual', - u'Raoul Snyman', 'manual'), + ('index', 'OpenLP.tex', u'OpenLP Documentation', + u'Wesley Stout', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -194,6 +191,12 @@ latex_documents = [ # not chapters. #latex_use_parts = False +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + # Additional stuff for the LaTeX preamble. #latex_preamble = '' @@ -201,10 +204,14 @@ latex_documents = [ #latex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +#latex_domain_indices = True -# A dictionary that contains LaTeX snippets that override those Sphinx usually -# puts into the generated .tex files. -latex_elements = { - 'fontpkg': '\\usepackage{helvet}' -} + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'openlp', u'OpenLP Documentation', + [u'Wesley Stout'], 1) +] diff --git a/documentation/manual/source/configure.rst b/documentation/manual/source/configure.rst new file mode 100644 index 000000000..9b4cc6f8f --- /dev/null +++ b/documentation/manual/source/configure.rst @@ -0,0 +1,363 @@ +================== +Configuring OpenLP +================== + +OpenLP has many options you can configure to suit your needs. Most options are +self-explanatory and we will quickly review them. + +To configure OpenLP, click on :menuselection:`Settings --> Configure OpenLP...` + +The plugins you have activated will have configure options. If all the plugins +are activated there will be 9 tabs across the top you can configure. + +General Tab +=========== + +.. image:: pics/configuregeneral.png + +Monitors +^^^^^^^^ +To select the monitor you want to display OpenLP on, click the drop-down box +and choose. + +Display if a single screen +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When this box is selected, you will be able to see your display on a separate +window on the monitor you are using. Click the display and push the Esc key +on your keyboard to close the display window. + +Application Startup +^^^^^^^^^^^^^^^^^^^ + +**Show blank screen warning:** + +When this box is selected, you will get a warning when opening OpenLP that the +output display has been blanked. You may have blanked it and shut down the +program and this will warn you it is still blanked. + +**Automatically open the last service:** + +When this box is selected, OpenLP will remember the last service you were +working on when you closed the program. + +**Show the splash screen:** + +When this box it selected, the OpenLP logo will be displayed in the center of +the screen until the program opens. This is useful to know if the program is +opening. + +Application Settings +^^^^^^^^^^^^^^^^^^^^ + +**Prompt to save before starting a new service** + +When this box is selected, OpenLP will prompt you to save the service you are +working on before starting a new service. + +**Automatically preview next item in service** + +When this box is selected, the next item in the Service Manager will show in the +Preview pane. + +**Slide loop delay** + +This setting is the time delay in seconds if you want to continuously loop +images, verses, or lyrics. This control timer is also accessible on the "live +toolbar. + +CCLI Details +^^^^^^^^^^^^ + +**CCLI number** + +If you subscribe to CCLI, this box is for your License number. This number is +also displayed in the Song Footer box. + +Display Position +^^^^^^^^^^^^^^^^ +This setting will default to your computer monitor. It will override the output +display combo box. If your projector display is different, select the Override +display position and make the changes here to match your projector display. This +option also comes in handy when you have the "Display if a single screen" box +selected. You can make the display smaller so it does not cover your whole +screen. + +Themes Tab +========== + +.. image:: pics/configurethemes.png + +Global Theme +^^^^^^^^^^^^ + +Choose the theme you would like to use as your default global theme from the +drop down box. The theme selected appears below. The global theme use is +determined by the Theme Level you have selected. + +Theme Level +^^^^^^^^^^^ + +Choose from one of three options for the default use of your theme. + +**Song Level:** + +With this level selected, your theme is associated with the song. The theme is +controlled by adding or editing a song in the Song editor and your song theme +takes priority. If your song does not have a theme associated with it, OpenLP +will use the theme set in the Service Manager. + +**Service Level:** + +With this level selected, your theme is controlled at the top of the Service +Manager. Select your default service theme there. This setting will override +your Song theme. + +**Global Level:** + +With this level selected, all songs and verses will use the theme selected on +the left in the Global Theme drop down. + +Advanced Tab +============ + +.. image:: pics/configureadvanced.png + + +UI Settings (user interface) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Number of recent files to display:** + +Set this number for OpenLP to remember your last files open. These will show +under File. + +**Remember active media manager tab on startup:** + +With this box selected OpenLP media manager will open on the same tab that it +was closed on. + +**Double-click to send items straight to live:** + +With this box selected, double-clicking on anything in the Media Manager will +immediately send it live instead of to Preview. + +**Expand new service items on creation:** + +With this box selected, everything you add to the Service Manager will be +expanded so you can see all the verses, lyrics and presentations, line by line. +When you open OpenLP, everything will automatically be expanded in the Service +Manager. + +Songs Tab +========= + +.. image:: pics/configuresongs.png + +Songs Mode +^^^^^^^^^^ + +**Enable search as you type:** + +With this box selected, Media Manager/Songs will display the song you are +searching for as you are typing. If this box is not selected, you need to type +in your search box and then click on the Search button. + +**Display verses on live tool bar:** + +With this box selected, a Go To drop down box is available on the live toolbar +to select any part of the verse type you want displayed live. + +**Update service from song edit:** + +With this box selected and you edit a song in the media manager, the results +will also change the song if it is added to the Service Manager. If this box +is not selected, your song edit changes will only be available in the Service +Manager if you add it again. + +**Add missing songs when opening service:** + +With this box selected, when you open an order of service created on another +computer, or if one of the songs are no longer in your Media Manager, it will +automatically enter the song in your Songs Media Manager. If this box is not +checked, the song is available in the service but will not be added to the +Media Manager. + +Bibles Tab +========== + +.. image:: pics/configurebibles.png + +Verse Display +^^^^^^^^^^^^^ + +**Only show new chapter numbers:** + +With this box selected, the live display of the verse will only show the +chapter number and verse for the first verse, and just the verse numbers after +that. If the chapter changes, the new chapter number will be displayed with the +verse number for the first line, and only the verse number displayed thereafter. + +**Display style:** + +This option will put brackets around the chapter and verse numbers. You may +select No Brackets or your bracket style from the drop down menu. + +**Layout style:** + +There are three options to determine how your Bible verses are displayed. + +`Verse Per Slide` will display one verse per slide. +`Verse Per Line` will start each verse on a new line until the slide is full. +`Continuous` will run all verses together separated by verse number and chapter +if chapter is selected to show above. + +**Note: Changes do not affect verses already in the service.** + +**Display second Bible verses:** + +OpenLP has the ability to display the same verse in two different Bible +versions for comparison. With this option selected, there will be a Second +choice in the Bible Media Manager to use this option. Verses will display with +one verse per slide with the second Bible verse below. + +**Bible theme:** + +You may select your default Bible theme from this drop down box. This selected +theme will only be used if your `Theme Level` is set at `Song Level`. + +**Note: Changes do not affect verses already in the service.** + + +Presentations Tab +================= + +.. image:: pics/configurepresentations.png + +Available Controllers +^^^^^^^^^^^^^^^^^^^^^ + +OpenLP has the ability to import OpenOffice Impress or Microsoft PowerPoint +presentations, and use Impress, PowerPoint, or PowerPoint Viewer to display +them and they are controlled from within OpenLP. Please remember that in order +to use this function, you must have Impress, PowerPoint or PowerPoint Viewer +installed on your computer because OpenLP uses these programs to open and run +the presentation. You may select your default controllers here in this tab. + +Advanced +^^^^^^^^ + +**Allow presentation application to be overridden** + +With this option selected, you will see `Present using` area with a dropdown +box on the Presentations toolbar in Media Manager which gives you the option +to select the presentation program you want to use. + +Media Tab +========= + +.. image:: pics/configuremedia.png + +Media Display +^^^^^^^^^^^^^ + +**Use Phonon for video playback** + +If you are having trouble displaying media, selecting this box could help. + +Custom Tab: +=========== + +.. image:: pics/configurecustom.png + +Custom Display +^^^^^^^^^^^^^^ + +**Display Footer** + +With this option selected, your Custom slide Title will be displayed in the +footer. + +**Note: If you have an entry in the Credits box of your custom slide, title and +credits will always be displayed.** + +Alerts Tab +========== + +.. image:: pics/configurealerts.png + +Font +^^^^ + +**Font name:** + +Choose your desired font from the drop down menu + +**Font color:** + +Choose your font color here. + +**Background color:** + +Choose the background color the font will be displayed on. + +**Font size:** + +This will adjust the size of the font. + +**Alert timeout:** + +This setting will determine how long your Alert will be displayed on the screen, +in seconds. + +**Location:** + +Choose the location where you want the alert displayed on the +screen, Top, Middle or Bottom. + +**Preview:** + +Your choices will be displayed here. + +Remote Tab +=========== + +.. image:: pics/configureremotes.png + +OpenLP gives you the ability to control your Service Manager from a remote +computer through a web browser. This was written actually for a nursery or day +care where a "come and get YYYY" message could be triggered remotely. It has +now become an interface to control the whole service remotely. + +An example of one use for this would be if you have a missionary with a +PowerPoint presentation, it may be easier for that missionary to remotely +connect to your projection computer and change the slides when he wants to. + +To use this feature you will need to be on a network, wired or wireless, know +the IP address of the projection computer and enter that IP address and port +number in the remote computer's web browser. + +To find your projection computer's IP address for Windows, open Command Prompt +and type in “ipconfig” (without quotations), press Enter key and your IP +address will show. In Linux, open Terminal and type “ifconfig” (without +quotations), and use the IP address after “inet addr:” The IP address will +always have a format of xxx.xxx.xxx.xxx where x is one to three digits long. + +Server Settings +^^^^^^^^^^^^^^^ + +Serve on IP address: Put your projection computer's IP address here. + +Port Number +^^^^^^^^^^^ + +You can use the default port number or change it to another number. + +With these two settings written down, open a web browser in the remote computer +and enter the IP address followed by a colon and then the port number, ie: +192.168.1.104:4316 then press enter. You should now have access to the OpenLP +Controller. If it does not come up, you either entered the wrong IP address, +port number or one or both computer's are not connected to the network. + + + diff --git a/documentation/manual/source/dualmonitors.rst b/documentation/manual/source/dualmonitors.rst index ee4bc90a2..5c29e8650 100644 --- a/documentation/manual/source/dualmonitors.rst +++ b/documentation/manual/source/dualmonitors.rst @@ -4,11 +4,11 @@ Dual Monitor Setup The first step in getting OpenLP working on your system is to setup your computer properly for dual monitors. This is not very difficult, but the steps -do vary depending on operating system. +will vary depending on operating system. -Most modern computers do have the ability for dual monitors. To be certain +Most modern computers have the ability for dual monitors. To be certain, check your computer's documentation. A typical desktop computer capable of dual -monitors will have two of, or a combination of the two connectors below. +monitors will have two of, or a combination of the two, connectors below. **VGA** @@ -18,8 +18,8 @@ monitors will have two of, or a combination of the two connectors below. .. image:: pics/dvi.png -A laptop computer setup only varies slightly, generally you will need only one -of outputs pictured above since your laptops screen serves as one of the +A laptop computer setup only varies slightly. Generally you will need only one +of the outputs pictured above since your laptop screen serves as one of the monitors. Sometimes with older laptops a key stroke generally involving the :kbd:`Fn` key and another key is required to enable the second monitor on laptops. @@ -27,9 +27,10 @@ laptops. Some computers also incorporate the use of :abbr:`S-Video (Separate Video)` or :abbr:`HDMI (High-Definition Multimedia Interface)` connections. -A typical OpenLP set up consist of your normal single monitor setup, with your -projector setup as the second monitor. With the option of extending your -desktop across the second monitor, or your operating system's equivalent. +A typical OpenLP setup consist of your normal single monitor, with your +projector hooked up to your computer as the second monitor. With the option of +extending your desktop across the second monitor, or your operating system's +equivalent. Microsoft Windows ----------------- @@ -46,8 +47,8 @@ press :kbd:`Windows+P`. The more traditional way is also fairly straight forward. Go to :guilabel:`Control Panel` and click on :guilabel:`Display`. This will open up -the :guilabel:`Display` dialog. You can also bypass this step by right click on -a blank area on your desktop and selecting :guilabel:`Resolution`. +the :guilabel:`Display` dialog. You may also bypass this step by a right click +on a blank area on your desktop and selecting :guilabel:`Resolution`. .. image:: pics/winsevendisplay.png @@ -66,7 +67,7 @@ a blank place on the desktop and click :guilabel:`Personalization`. .. image:: pics/vistapersonalize.png From the :guilabel:`Personalization` window click on :guilabel:`Display -Settings`. Then enable the montior that represents your projector and make sure +Settings`. Click on the monitor that represents your projector and make sure you have checked :guilabel:`Extend the desktop onto this monitor`. .. image:: pics/vistadisplaysettings.png @@ -77,7 +78,7 @@ Windows XP From :guilabel:`Control Panel` select :guilabel:`Display`, or right click on a blank area of the desktop and select :guilabel:`Properties`. From the :guilabel:`Display Properties` window click on the :guilabel:`Settings` tab. -Then click on the monitor that represents your projector and make sure you have +Click on the monitor that represents your projector and make sure you have checked :guilabel:`Extend my Windows desktop onto this monitor`. .. image:: pics/xpdisplaysettings.png @@ -87,7 +88,7 @@ Linux Due to the vast varieties of hardware, distributions, desktops, and drivers this is not an exhaustive guide to dual monitor setup on Linux. This guide -assumes that you have properly set up any proprietary drivers if needed. You +assumes you have properly set up any proprietary drivers if needed. You should seek out your distributions documentation if this general guide does not work. @@ -123,7 +124,8 @@ Linux Systems Using nVidia Drivers This guide is for users of the proprietary nVidia driver on Linux Distributions. It is assumed that you have properly setup your drivers according to your -distribution's documentation, and you have a working ``xorg.conf`` file in place. +distribution's documentation, and you have a working ``xorg.conf`` file in +place. If you wish to make the changes permanent in setting up your system for dual monitors it will be necessary to modify your ``xorg.conf`` file. It is always a @@ -166,7 +168,7 @@ After clicking :guilabel:`Configure`, select :guilabel:`TwinView`. Then click .. image:: pics/twinview.png -Then click :guilabel:`Apply` and if you are happy with the way things look click +Click :guilabel:`Apply` and if you are happy with the way things look click :guilabel:`Keep` to keep your new settings. Don't worry if all goes wrong the settings will return back to the previous settings in 15 seconds without any action. nVidia Settings should take care of selecting your optimum resolution @@ -175,6 +177,6 @@ on :guilabel:`Save to X Configuration File`. .. image:: pics/xorgwrite.png -Then click :guilabel:`Save` and you should be set. You may want to restart X or +Click :guilabel:`Save` and you should be set. You may want to restart X or your machine just to make sure all the settings carry over the next time you log in. diff --git a/documentation/manual/source/glossary.rst b/documentation/manual/source/glossary.rst index 6f4ebcdd6..fd00f4842 100644 --- a/documentation/manual/source/glossary.rst +++ b/documentation/manual/source/glossary.rst @@ -18,13 +18,19 @@ The Main Window contains all the tools and plugins that make OpenLP function Media Manager ------------- -The Media Manager contains a number of tabs that plugins supply to OpenLP. +The Media Manager contains a number of tabs the plugins supply to OpenLP. Each tab in the Media Manager is called a **Media Item** .. image:: pics/mediamanager.png From the Media Manager you can send Media Items to the Preview or Live screens. +Platform +-------- + +When the word platform is used, it is usually referring to your operating system, +Windows, Linux or MAC OS. + Preview ------- @@ -36,20 +42,20 @@ with them. Service File ------------ -A service file, is the file that is created when you save your work on OpenLP. +A service file is the file that is created when you save your service in OpenLP. The service file consist of **Service Items** Service Item ------------ -A service item are the **media items** that are in the **service manager** +Service items are the **media items** that are in the **service manager** Service Manger -------------- The service manager contains the media items in your service file. This is the -area from which your media items go live, and you can also save, open, and edit -services files. +area where your media items go live. You can also save, open, and edit +services files from here. .. image:: pics/servicemanager.png @@ -65,6 +71,6 @@ Theme Manager ------------- The theme manager is where themes are created and edited. Themes are the text -styles backgrounds that you use to personalize your services. +styles and backgrounds that you use to personalize your services. .. image:: pics/thememanager.png diff --git a/documentation/manual/source/index.rst b/documentation/manual/source/index.rst index 378cfe2a0..6e8753f9f 100644 --- a/documentation/manual/source/index.rst +++ b/documentation/manual/source/index.rst @@ -14,6 +14,8 @@ Contents: introduction glossary dualmonitors + configure + bibles + themes mediamanager - songs - + songs \ No newline at end of file diff --git a/documentation/manual/source/mediamanager.rst b/documentation/manual/source/mediamanager.rst index 2cf1d2c57..778ae8ccd 100644 --- a/documentation/manual/source/mediamanager.rst +++ b/documentation/manual/source/mediamanager.rst @@ -3,8 +3,8 @@ Media Manager ============= Once you get your system set up for OpenLP you will be ready to add content to -your setup. This will all happen through the **Media Manager**. The -`Media Manager` contains all the bibles, songs, presentations, media, and +your Service Manager. This will all happen through the **Media Manager**. The +`Media Manager` contains all the Bibles, Songs, Presentations, Media, and everything else that you will project through OpenLP. Enabling the Plugins @@ -16,11 +16,235 @@ this is what the `Media Manager` looks like with all the plugins enabled. .. image:: pics/mediamanager.png To enable the plugins navigate to :menuselection:`Settings --> Plugins` or -press `F7`. You will then want to click on the plugin to the left that you want -to enable and select **active** from the drop down box to the right. +press `F7`. You will want to click on the plugin to the left that you want to +enable and select **active** from the drop down box to the right. .. image:: pics/plugins.png -Now you should be ready to add content to OpenLP check out the section of this -guide on the individual plugins. +You are now ready to add content for your service. + +Adding Media Content +-------------------- + +This section will describe how to add the different types of media OpenLP is +capable of displaying. + +Songs +^^^^^ +Clicking on Songs in the Media Manager will display all of the songs you have +added by Title and Author/Authors. + +Using the buttons you can: + +`Add a song:` Brings up the dialog box to add a new song + +`Edit the selected song:` Brings up the dialog box to make changes to the song + +`Delete the selected song:` Removes the song from your song list + +`Preview the selected song:` Lets you see what your song will look like +displayed live + +`Send the selected song live:` This option will immediately display your song +live. + +`Add the selected Song to the service:` This will enter your song in the Service +Manager. You may also drag your song over to the Service Manager. + +`Maintain the list of authors, topics and books:` Brings up a dialog box to edit +Authors, Topics or Song Books. +Note: Right clicking on a song file will bring up some of the same options. + +Bibles +^^^^^^ +Clicking on Bibles in the Media Manager will display your options for searching +and adding chapters and verses to the Service Manager. + +Using the buttons you can: + +`Import a Bible:` This is discussed in detail on the Bible Importer page in the +manual. + +`Preview the selected Bible:` Sends your selected verses to the Preview window + +`Send the selected Bible live:` This option will immediately display your +selected verses live. + +`Add the selected Bible to the service:` This will enter your verses into the +Service Manager. You may also click and drag your verses over to the Service +Manager. + +**Quick tab** + +`Version:` Once you have imported a Bible, it will be displayed in the Version +drop down box. Select the version of the Bible you want to use here. + +**Second** + +If you have “Display second Bible verses” selected in Configure OpenLP, Bibles +tab, this choice will be visible. This option is for displaying another version +of the Bible for comparison. Both versions will be displayed. If there is not +enough space on one slide, the Second version will be displayed on the next +slide. + +Use the `Search` button to display your results in the box below. + +**Find** + +You will type your search query in this box for the following two searches. + +`Search type:` You may search for a specific verse using this format below. + +Book Chapter +Book Chapter-Chapter +Book Chapter:Verse-Verse +Book Chapter:Verse-Verse, Verse-Verse +Book Chapter:Verse-Verse,Chapter:Verse-Verse +Book Chapter: Verse-Chapter:Verse + +`Text Search:` + +You may also search by a keyword or words. The more words you use for the +search, the more you will narrow down your results. + +**Results** `Clear and Keep.` + +Each search you make will display your verses below. If you would like to +display verses that are out of sequence you may select `Keep` in the drop down +box and continue your search for the next verse or verses. All searches will be +shown and kept below. +If you select `Clear` from the drop down box, each new search clears the +previous search from the list below. + +**Advanced tab** + +This tab is convenient for selecting book, chapter and verse by name and number. +Version and Second are the same as in Quick tab above. Click on each box and +select the version you wish to display and Second version if you wish to display +an alternative version. + +Use the `Search` button to display your results in the box below. + +`Book:` Click on the drop down box and select the book you want to display. +`Chapter: Verse:` Select your chapter From and To and Verse From and To + +Results will work the same as the Quick tab above. + +Presentations +^^^^^^^^^^^^^ +Using the buttons you can: + +`Load a new presentation:` This brings up a dialog box to find your presentation +and list it in OpenLP. + +`Delete the selected Presentation:` This removes your Presentation from the list. +Please note: this will not delete the presentation from your computer, only from +the OpenLP list. + +`Preview the selected Presentation:` Sends your selected Presentation to the +Preview window + +`Send the selected Presentation live:` This option will immediately display your +selected Presentation live. + +`Add the selected Presentation to the service:` This will enter your +Presentation into the Service Manager. You may also click and drag your +Presentation over to the Service Manager. + +Right clicking on a Presentation file will bring up some of the same options. + +Images +^^^^^^ +Using the buttons you can: + +`Load a new Image:` This brings up a dialog box to find your Image and list it +in OpenLP. + +`Delete the selected Image:` This removes your Image from the list. Please note: +this will not delete the Image from your computer, just the OpenLP list. + +`Preview the selected Image:` Sends your selected Image to the Preview window + +`Send the selected Image live:` This option will immediately display your +selected Image live. + +`Add the selected Image to the service:` This will enter your Image into the +Service Manager. You may also click and drag your Image over to the Service +Manager. + +`Replace Live Background:` With an Image selected, clicking this button will +immediately replace the live background being displayed with your selection. +The Image will replace the theme background until the theme changes or the +"Remove Background" button is pressed. + + +Right clicking on an Image file will bring up some of the same options. + +Media +^^^^^ + +Media is an audio or video file. Generally if you can play or view your media +on your computer without OpenLP, you can also play it in OpenLP. + +Using the buttons you can: +`Load a new Media:` This brings up a dialog box to find your Media and list it +in OpenLP. + +`Delete the selected Media:` This removes your Media from the list. Please note: +this will not delete the Media from your computer, just the OpenLP list. + +`Preview the selected Media:` Sends your selected Media to the Preview window + +`Send the selected Media live:` This option will immediately display your +selected Media live. + +`Add the selected Media to the service:` This will enter your Media into the +Service Manager. You may also click and drag your Media over to the Service +Manager. + +`Replace Live Background:` With a Media file selected, clicking this button will +immediately replace the live background being displayed with your selection. + +Right clicking on a Media file will bring up some of the same options. + +Custom +^^^^^^ + +Custom gives you the option of creating your own slide. This could be useful for +displaying readings, liturgy or any text that may not be found in Songs or +Bibles. + +`Add a new Custom:` Brings up the dialog box to add a new Custom display. +`Edit the selected Custom:` Brings up the dialog box to make changes to the +Custom display. + +`Delete the selected Custom:` Remove the Custom from your list + +`Preview the selected Custom:` Lets you see what your Custom will look like +displayed live + +`Send the selected Custom live:` This option will immediately display your +Custom live + +`Add the selected Custom to the service:` This will enter your Custom in the +Service Manager. You may also drag your Custom over to the Service Manager. + +Right clicking on a Custom file will bring up some of the same options. + +When you Add a new Custom slide a dialog box will appear. + +`Title:` Name of your Custom slide. + +`Add:` After clicking on Add you will enter your text you want to display in +this box. To create multiple slides, click the Split Slide button. When you have +finished adding your text, click on the Save button. + +`Theme:` Select the theme you want to use for your Custom slide from this drop +down box. +`Credits:` Anything typed in this box will be displayed in the footer +information on the display. When you are finished, click the Save button. + +To Edit your slide, click on the Edit button to edit part of it or the Edit All +if you need to make multiple changes. Use the Up and Down arrows to change the +arrangement of your Custom slide. diff --git a/documentation/manual/source/pics/addsong.png b/documentation/manual/source/pics/addsong.png new file mode 100644 index 000000000..3bcdfc088 Binary files /dev/null and b/documentation/manual/source/pics/addsong.png differ diff --git a/documentation/manual/source/pics/addsongservice1.png b/documentation/manual/source/pics/addsongservice1.png new file mode 100644 index 000000000..1a01edadb Binary files /dev/null and b/documentation/manual/source/pics/addsongservice1.png differ diff --git a/documentation/manual/source/pics/addsongservice2.png b/documentation/manual/source/pics/addsongservice2.png new file mode 100644 index 000000000..4be2728d0 Binary files /dev/null and b/documentation/manual/source/pics/addsongservice2.png differ diff --git a/documentation/manual/source/pics/authorstopicsbooks.png b/documentation/manual/source/pics/authorstopicsbooks.png new file mode 100644 index 000000000..dd7aa4862 Binary files /dev/null and b/documentation/manual/source/pics/authorstopicsbooks.png differ diff --git a/documentation/manual/source/pics/bibleimport01.png b/documentation/manual/source/pics/bibleimport01.png new file mode 100644 index 000000000..be8bdfbf3 Binary files /dev/null and b/documentation/manual/source/pics/bibleimport01.png differ diff --git a/documentation/manual/source/pics/bibleimport02.png b/documentation/manual/source/pics/bibleimport02.png new file mode 100644 index 000000000..23c4b7b2a Binary files /dev/null and b/documentation/manual/source/pics/bibleimport02.png differ diff --git a/documentation/manual/source/pics/bibleimportdetails1.png b/documentation/manual/source/pics/bibleimportdetails1.png new file mode 100644 index 000000000..519c36922 Binary files /dev/null and b/documentation/manual/source/pics/bibleimportdetails1.png differ diff --git a/documentation/manual/source/pics/bibleimportfinished1.png b/documentation/manual/source/pics/bibleimportfinished1.png new file mode 100644 index 000000000..15fbd7bae Binary files /dev/null and b/documentation/manual/source/pics/bibleimportfinished1.png differ diff --git a/documentation/manual/source/pics/biblewebcomplete.png b/documentation/manual/source/pics/biblewebcomplete.png new file mode 100644 index 000000000..a928f8021 Binary files /dev/null and b/documentation/manual/source/pics/biblewebcomplete.png differ diff --git a/documentation/manual/source/pics/configureadvanced.png b/documentation/manual/source/pics/configureadvanced.png new file mode 100644 index 000000000..f31812f93 Binary files /dev/null and b/documentation/manual/source/pics/configureadvanced.png differ diff --git a/documentation/manual/source/pics/configurealerts.png b/documentation/manual/source/pics/configurealerts.png new file mode 100644 index 000000000..ac46801dc Binary files /dev/null and b/documentation/manual/source/pics/configurealerts.png differ diff --git a/documentation/manual/source/pics/configurebibles.png b/documentation/manual/source/pics/configurebibles.png new file mode 100644 index 000000000..cd44ee4af Binary files /dev/null and b/documentation/manual/source/pics/configurebibles.png differ diff --git a/documentation/manual/source/pics/configurecustom.png b/documentation/manual/source/pics/configurecustom.png new file mode 100644 index 000000000..3db5c4989 Binary files /dev/null and b/documentation/manual/source/pics/configurecustom.png differ diff --git a/documentation/manual/source/pics/configuregeneral.png b/documentation/manual/source/pics/configuregeneral.png new file mode 100644 index 000000000..b1bae76e0 Binary files /dev/null and b/documentation/manual/source/pics/configuregeneral.png differ diff --git a/documentation/manual/source/pics/configuremedia.png b/documentation/manual/source/pics/configuremedia.png new file mode 100644 index 000000000..cc9e11a38 Binary files /dev/null and b/documentation/manual/source/pics/configuremedia.png differ diff --git a/documentation/manual/source/pics/configurepresentations.png b/documentation/manual/source/pics/configurepresentations.png new file mode 100644 index 000000000..4960aa8e5 Binary files /dev/null and b/documentation/manual/source/pics/configurepresentations.png differ diff --git a/documentation/manual/source/pics/configureremotes.png b/documentation/manual/source/pics/configureremotes.png new file mode 100644 index 000000000..9eb22131c Binary files /dev/null and b/documentation/manual/source/pics/configureremotes.png differ diff --git a/documentation/manual/source/pics/configuresongs.png b/documentation/manual/source/pics/configuresongs.png new file mode 100644 index 000000000..19796f3b5 Binary files /dev/null and b/documentation/manual/source/pics/configuresongs.png differ diff --git a/documentation/manual/source/pics/configurethemes.png b/documentation/manual/source/pics/configurethemes.png new file mode 100644 index 000000000..c8241ddaf Binary files /dev/null and b/documentation/manual/source/pics/configurethemes.png differ diff --git a/documentation/manual/source/pics/createthemeicon.png b/documentation/manual/source/pics/createthemeicon.png new file mode 100644 index 000000000..d1fefc0d2 Binary files /dev/null and b/documentation/manual/source/pics/createthemeicon.png differ diff --git a/documentation/manual/source/pics/csvimport1.png b/documentation/manual/source/pics/csvimport1.png new file mode 100644 index 000000000..9a4214aec Binary files /dev/null and b/documentation/manual/source/pics/csvimport1.png differ diff --git a/documentation/manual/source/pics/csvimport2.png b/documentation/manual/source/pics/csvimport2.png new file mode 100644 index 000000000..d0c8e569b Binary files /dev/null and b/documentation/manual/source/pics/csvimport2.png differ diff --git a/documentation/manual/source/pics/logo.png b/documentation/manual/source/pics/logo.png new file mode 100644 index 000000000..a232b59a9 Binary files /dev/null and b/documentation/manual/source/pics/logo.png differ diff --git a/documentation/manual/source/pics/openlp.ico b/documentation/manual/source/pics/openlp.ico new file mode 100644 index 000000000..e53fce8d7 Binary files /dev/null and b/documentation/manual/source/pics/openlp.ico differ diff --git a/documentation/manual/source/pics/previewsong1.png b/documentation/manual/source/pics/previewsong1.png new file mode 100644 index 000000000..23a6b2a07 Binary files /dev/null and b/documentation/manual/source/pics/previewsong1.png differ diff --git a/documentation/manual/source/pics/previewsong2.png b/documentation/manual/source/pics/previewsong2.png new file mode 100644 index 000000000..6202e0d14 Binary files /dev/null and b/documentation/manual/source/pics/previewsong2.png differ diff --git a/documentation/manual/source/pics/sendsonglive1.png b/documentation/manual/source/pics/sendsonglive1.png new file mode 100644 index 000000000..abef56775 Binary files /dev/null and b/documentation/manual/source/pics/sendsonglive1.png differ diff --git a/documentation/manual/source/pics/sendsonglive2.png b/documentation/manual/source/pics/sendsonglive2.png new file mode 100644 index 000000000..5700495f3 Binary files /dev/null and b/documentation/manual/source/pics/sendsonglive2.png differ diff --git a/documentation/manual/source/pics/songeditor1.png b/documentation/manual/source/pics/songeditor1.png new file mode 100644 index 000000000..d34e10165 Binary files /dev/null and b/documentation/manual/source/pics/songeditor1.png differ diff --git a/documentation/manual/source/pics/songeditor11.png b/documentation/manual/source/pics/songeditor11.png new file mode 100644 index 000000000..0d25eb097 Binary files /dev/null and b/documentation/manual/source/pics/songeditor11.png differ diff --git a/documentation/manual/source/pics/songeditor2.png b/documentation/manual/source/pics/songeditor2.png new file mode 100644 index 000000000..e9f02fd16 Binary files /dev/null and b/documentation/manual/source/pics/songeditor2.png differ diff --git a/documentation/manual/source/pics/songeditor3.png b/documentation/manual/source/pics/songeditor3.png new file mode 100644 index 000000000..4c567ab29 Binary files /dev/null and b/documentation/manual/source/pics/songeditor3.png differ diff --git a/documentation/manual/source/pics/songeditor4.png b/documentation/manual/source/pics/songeditor4.png new file mode 100644 index 000000000..b8fe6be9c Binary files /dev/null and b/documentation/manual/source/pics/songeditor4.png differ diff --git a/documentation/manual/source/pics/songeditor5.png b/documentation/manual/source/pics/songeditor5.png new file mode 100644 index 000000000..bfc9aba75 Binary files /dev/null and b/documentation/manual/source/pics/songeditor5.png differ diff --git a/documentation/manual/source/pics/songeditor6.png b/documentation/manual/source/pics/songeditor6.png new file mode 100644 index 000000000..e727b3828 Binary files /dev/null and b/documentation/manual/source/pics/songeditor6.png differ diff --git a/documentation/manual/source/pics/songeditor7.png b/documentation/manual/source/pics/songeditor7.png new file mode 100644 index 000000000..eeb6f0ff1 Binary files /dev/null and b/documentation/manual/source/pics/songeditor7.png differ diff --git a/documentation/manual/source/pics/songeditor8.png b/documentation/manual/source/pics/songeditor8.png new file mode 100644 index 000000000..fd57d79b4 Binary files /dev/null and b/documentation/manual/source/pics/songeditor8.png differ diff --git a/documentation/manual/source/pics/songeditor9.png b/documentation/manual/source/pics/songeditor9.png new file mode 100644 index 000000000..cf067a7dc Binary files /dev/null and b/documentation/manual/source/pics/songeditor9.png differ diff --git a/documentation/manual/source/pics/songs12.png b/documentation/manual/source/pics/songs12.png new file mode 100644 index 000000000..d9637a4d0 Binary files /dev/null and b/documentation/manual/source/pics/songs12.png differ diff --git a/documentation/manual/source/pics/songs13.png b/documentation/manual/source/pics/songs13.png new file mode 100644 index 000000000..2d084954c Binary files /dev/null and b/documentation/manual/source/pics/songs13.png differ diff --git a/documentation/manual/source/pics/songs14.png b/documentation/manual/source/pics/songs14.png new file mode 100644 index 000000000..917bb6bf6 Binary files /dev/null and b/documentation/manual/source/pics/songs14.png differ diff --git a/documentation/manual/source/pics/songs15.png b/documentation/manual/source/pics/songs15.png new file mode 100644 index 000000000..74deea0ec Binary files /dev/null and b/documentation/manual/source/pics/songs15.png differ diff --git a/documentation/manual/source/pics/songs16.png b/documentation/manual/source/pics/songs16.png new file mode 100644 index 000000000..e72026839 Binary files /dev/null and b/documentation/manual/source/pics/songs16.png differ diff --git a/documentation/manual/source/pics/songs17.png b/documentation/manual/source/pics/songs17.png new file mode 100644 index 000000000..c5b56d1eb Binary files /dev/null and b/documentation/manual/source/pics/songs17.png differ diff --git a/documentation/manual/source/pics/themeeditbutton.png b/documentation/manual/source/pics/themeeditbutton.png new file mode 100644 index 000000000..b3e6a768b Binary files /dev/null and b/documentation/manual/source/pics/themeeditbutton.png differ diff --git a/documentation/manual/source/pics/themeimportexport.png b/documentation/manual/source/pics/themeimportexport.png new file mode 100644 index 000000000..189a2a435 Binary files /dev/null and b/documentation/manual/source/pics/themeimportexport.png differ diff --git a/documentation/manual/source/pics/thememanager1.png b/documentation/manual/source/pics/thememanager1.png new file mode 100644 index 000000000..24dd6bec0 Binary files /dev/null and b/documentation/manual/source/pics/thememanager1.png differ diff --git a/documentation/manual/source/pics/themewizard1.png b/documentation/manual/source/pics/themewizard1.png new file mode 100644 index 000000000..1e37687fb Binary files /dev/null and b/documentation/manual/source/pics/themewizard1.png differ diff --git a/documentation/manual/source/pics/themewizard2.png b/documentation/manual/source/pics/themewizard2.png new file mode 100644 index 000000000..ba1654daf Binary files /dev/null and b/documentation/manual/source/pics/themewizard2.png differ diff --git a/documentation/manual/source/pics/themewizard3.png b/documentation/manual/source/pics/themewizard3.png new file mode 100644 index 000000000..508e80c1c Binary files /dev/null and b/documentation/manual/source/pics/themewizard3.png differ diff --git a/documentation/manual/source/pics/themewizard4.png b/documentation/manual/source/pics/themewizard4.png new file mode 100644 index 000000000..9cd50ed67 Binary files /dev/null and b/documentation/manual/source/pics/themewizard4.png differ diff --git a/documentation/manual/source/pics/themewizard5.png b/documentation/manual/source/pics/themewizard5.png new file mode 100644 index 000000000..cb5c0813c Binary files /dev/null and b/documentation/manual/source/pics/themewizard5.png differ diff --git a/documentation/manual/source/pics/themewizard6.png b/documentation/manual/source/pics/themewizard6.png new file mode 100644 index 000000000..9958d43f0 Binary files /dev/null and b/documentation/manual/source/pics/themewizard6.png differ diff --git a/documentation/manual/source/pics/themewizard7.png b/documentation/manual/source/pics/themewizard7.png new file mode 100644 index 000000000..92d9e47ac Binary files /dev/null and b/documentation/manual/source/pics/themewizard7.png differ diff --git a/documentation/manual/source/pics/themewizard8.png b/documentation/manual/source/pics/themewizard8.png new file mode 100644 index 000000000..a25cf0d8c Binary files /dev/null and b/documentation/manual/source/pics/themewizard8.png differ diff --git a/documentation/manual/source/pics/themewizard9.png b/documentation/manual/source/pics/themewizard9.png new file mode 100644 index 000000000..2bde33ac7 Binary files /dev/null and b/documentation/manual/source/pics/themewizard9.png differ diff --git a/documentation/manual/source/pics/themewizardwelcome.png b/documentation/manual/source/pics/themewizardwelcome.png new file mode 100644 index 000000000..f58e7c8f3 Binary files /dev/null and b/documentation/manual/source/pics/themewizardwelcome.png differ diff --git a/documentation/manual/source/pics/webbible1.png b/documentation/manual/source/pics/webbible1.png new file mode 100644 index 000000000..6ff1b6560 Binary files /dev/null and b/documentation/manual/source/pics/webbible1.png differ diff --git a/documentation/manual/source/pics/webbibleproxy1.png b/documentation/manual/source/pics/webbibleproxy1.png new file mode 100644 index 000000000..23ba9ad24 Binary files /dev/null and b/documentation/manual/source/pics/webbibleproxy1.png differ diff --git a/documentation/manual/source/quickstart.rst b/documentation/manual/source/quickstart.rst new file mode 100644 index 000000000..81e262125 --- /dev/null +++ b/documentation/manual/source/quickstart.rst @@ -0,0 +1,11 @@ +======================== +OpenLP Quick Start Guide +======================== + +Thank you for choosing OpenLP. The developers of OpenLP have attempted to make +OpenLP intuitive and easy to use. This Quick Start Guide will help you to get +going quickly. + +Bible Importer +============== + diff --git a/documentation/manual/source/songs.rst b/documentation/manual/source/songs.rst index 678a6206c..91e5539c2 100644 --- a/documentation/manual/source/songs.rst +++ b/documentation/manual/source/songs.rst @@ -8,26 +8,26 @@ converters provided to get data from other formats into OpenLP. Song Importer ============= -If you are using an earlier version of OpenLP or come from another software +If you are using an earlier version of OpenLP or, come from another software package, you may be able to convert your existing database to work in OpenLP -2.0. To access the Song Importer :menuselection:`File --> Import --> Song`. -You will then see the Song Importer window, then click :guilabel:`Next`. +2.0. To access the Song Importer click :menuselection:`File --> Import --> Song`. +You will see the Song Importer window, then click :guilabel:`Next`. .. image:: pics/songimporter.png -After choosing :guilabel:`Next` you can then select from the various types of +After choosing :guilabel:`Next` you can select from the various types of software that OpenLP will convert songs from. .. image:: pics/songimporterchoices.png -Then click on the file folder icon to choose the file of the song database you +Click on the file folder icon to choose the file of the song database you want to import. See the following sections for information on the different formats that OpenLP will import. Importing from OpenLP Version 1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Converting from OpenLP Version 1 is a pretty simple process. You will first +Converting from OpenLP Version 1 is a simple process. First you will need to locate your version 1 database file. Windows XP:: @@ -38,33 +38,34 @@ Windows Vista / Windows 7:: C:\ProgramData\openlp.org\Data\songs.olp -After clicking :guilabel:`Next` your conversion should be complete. +After clicking :guilabel:`Next` your conversion will be complete. .. image:: pics/finishedimport.png -Then press :guilabel:`Finish` and you should now be ready to use your OpenLP -version one songs. +Press :guilabel:`Finish` and you will now be ready to use your OpenLP +version 1 songs. Importing from OpenSong ^^^^^^^^^^^^^^^^^^^^^^^ -Converting from OpenSong you will need to locate your songs database. In the +Converting from OpenSong, you will need to locate your songs database. In the later versions of OpenSong you are asked to define the location of this. The -songs will be located in a folder named :guilabel:`Songs`. This folder should -contain files with all your songs in them without a file extension. (file.xxx). -When you have located this folder you will then need to select the songs from +songs will be located in a folder named :guilabel:`Songs`. This folder will +contain files with all your songs in them, without a file extension. (file.xxx). +When you have located this folder you will need to select the songs from the folder. .. image:: pics/selectsongs.png -On most operating systems to select all the songs, first select the first song -in the lest then press shift and select the last song in the list. After this -press :guilabel:`Next` and you should see that your import has been successful. +On most operating systems, to select all the songs, first select the first song +in the list, press the shift key, and select the last song in the list. After +this press :guilabel:`Next` and you will see that your import has been +successful. .. image:: pics/finishedimport.png -Press :guilabel:`Finish` and you will now be ready to use your songs imported -from OpenSong. +Press :guilabel:`Finish` and OpenLP will be ready to use your songs that you +imported from OpenSong. Importing from CCLI Song Select ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,22 +80,23 @@ Then search for your desired song. For this example we will be adding the song .. image:: pics/songselectsongsearch.png -For the song you are searching for select `lyrics` This should take you to a -page displaying the lyrics and copyright info for your song. +For the song you are searching for, select `lyrics` This will take you to a +page displaying the lyrics and copyright information for your song. .. image:: pics/songselectlyrics.png -Next, hover over the :guilabel:`Lyrics` menu from the upper right corner. Then -choose either the .txt or .usr file. You will then be asked to chose a download +Next, hover over the :guilabel:`Lyrics` menu from the upper right corner. +Choose either the .txt or .usr file. You will be asked to chose a download location if your browser does not automatically select that for you. Select this file from the OpenLP import window and then click :guilabel:`Next` You can also select multiple songs for import at once on most operating systems by -selecting the first item in the list then holding shift select the last item in -the list. When finished you should see that your import has completed. +selecting the first item in the list then holding the shift key and select the +last item in the list. When finished, you will see that your import has +completed. .. image:: pics/finishedimport.png -Press :guilabel:`Finish` and you will now be ready to use your songs imported +Press :guilabel:`Finish` and OpenLP will be ready to use your songs imported from CCLI SongSelect. diff --git a/documentation/manual/source/themes.rst b/documentation/manual/source/themes.rst new file mode 100644 index 000000000..b689cb1a8 --- /dev/null +++ b/documentation/manual/source/themes.rst @@ -0,0 +1,196 @@ +====== +Themes +====== + + +The `Theme Manager` is where you can set backgrounds, fonts, and colors to the +style you desire. From the theme manager you can create a new theme, Edit a +theme, Delete a theme, Import a theme, and Export a theme. + +.. image:: /pics/thememanager1.png + +Creating New Themes +=================== +Click the :guilabel:`Create Theme Icon` to Create a new theme + +.. image:: /pics/createthemeicon.png + +This will bring up the `Theme Wizard` + +.. image:: /pics/themewizardwelcome.png + +Click :guilabel:`Next`. You have 3 choices in the drop down menu for Background +type: Solid Color, Gradient, or Image. + +.. image:: /pics/themewizard1.png + +Solid color: select solid color and click on the black button next to Color. +You will have the option of choosing among the colors you see or entering your +own. + +.. image:: /pics/themewizard2.png + +Gradient: choose the two colors, First and Second, you want to fade together +and the Gradient drop down will let you determine the directions of the fade. + +.. image:: /pics/themewizard3.png + +Image: Click on the folder to find and select your image. OpenLP accepts a +variety of image types. + +.. image:: /pics/themewizard4.png + +**Note:** If possible, try to use the same size image as your projector is +displaying. + +When finished with your selection for background, click the :guilabel:`Next` +button. + +This is the area where you will select and define your font characteristics for +the Display text. + +.. image:: /pics/themewizard5.png + +**Font:** Choose the font you would like to use from the drop down. + +**Color:** Choose the color of your font. + +**Size:** The size of your font determines how many lines are shown per slide. +As you change the font size, the lines per slide will change. + +**Line Spacing:** This setting determines how much space you want between +lines. This setting will also change the lines per slide. + +**Outline:** If you desire an outline around your font, select the Outline box, +choose your color and size of the outline. + +**Shadow:** If you desire a shadow around your font, select the Shadow box and +choose your color and size of the shadow. + +**Bold Display:** select the box for Bold font + +**Italic Display:** select the box for Italic font + +When you are finished selecting your font details click the :guilabel:`Next` +button. + +**Footer Area Font Details** + +This page determines the Font, Font Color, and size of the font for the footer. +The footer is where the Title of the song, Author or Authors, Copyright and +CCLI License are displayed. + +.. image:: /pics/themewizard6.png + +When you are finished setting your footer font details, click :guilabel:`Next`. + +**Text Formatting Details** + +This page determines the alignment of the text on your slide and the transition +from one slide to the next. + +.. image:: /pics/themewizard7.png + +**Horizontal Align** the text to the Left, Right or Center of the screen. + +**Vertical Align** the text to the Top, Middle or bottom of the screen. + +**Transitions** + +When this box is selected, switching slides will fade out from one and fade in +to the next. When the box is not selected, slide changing will be instant. + +When you are finished setting your Text Formatting Details, click :guilabel:`Next`. + +**Output Area Locations** + +This page gives you the ability to position your Main area or Footer area to a +specific area of the screen using the x and y positions. ie: if you do not want +your footer on the bottom left, you can make the adjustment here. +You can resize the Width and the Height of the Main Area and the Footer Area. +ie: If you have a temporary or permanent obstacle in one part of the viewing +area, you can resize the Main or Footer area and use x and y positions to +display in a different position on the screen. + +.. image:: /pics/themewizard8.png + +You can also change the Width and the Height of the Main Area of the Footer Area. + +When you are finished setting your Output Area Locations, click :guilabel:`Next`. + +Save and Preview + +.. image:: /pics/themewizard9.png + +**Theme Name:** Enter your theme name here. + +**Preview** +The Preview shows the choices you made when setting up the previous pages plus, +shows all the edit effects possible so you can see what the impact is on all +possible font colors and characteristics. + +If you are satisfied with your selections, click :guilabel:`Finish`. If you +want to make a change, use the :guilabel:`Back` button. + +Editing Themes +============== +Now that you created your theme, and you show it on the projector and there is +something you don't like, you can easily Edit your theme either by clicking the +Theme Edit Button: + +.. image:: /pics/themeeditbutton.png + +Or by right-clicking your theme and selecting the appropriate action. + +Deleting Themes +=============== + +The Delete Button: + +.. image:: /pics/songs17.png + +will delete a selected theme or by right-clicking your theme and selecting +the appropriate action. + +**Note:** deleting the currently selected global theme or the +default theme is not possible. + +Exporting Themes +================ +If you would like to transfer a theme from one computer to another, click on +the theme you want to Export, click the last button in the Theme Manager: + +.. image:: /pics/themeimportexport.png + +choose the folder you want to save your theme and click the OK button. + +Importing Themes +================ + +The fourth button in the Theme Manager: + +.. image:: /pics/themeimportexport.png + +will allow you to Import an Exported theme. Click the Import button, select the +folder and the theme file, and click OK. Your imported theme will be in the +Theme Manager. Import Theme will also handle version 1 Exports. You will need to +check your imported theme since many of the values will have been defaulted. + +Rename Theme +============ + +If you created a theme and want to change the name of it, right-click your +theme and click Rename theme and enter the new name. + +Copy Theme +========== + +Now that you created a theme with all the attributes you like, you can +right-click the theme, click on Copy theme, choose your new name and click OK. +You now have a duplicate of your first theme that you can edit the way you want. + +Set as Global default +===================== + +If you right-click your theme, you have the option to set the theme as Global +default. This option is covered in greater detail under “Configure OpenLP. diff --git a/openlp.pyw b/openlp.pyw index ad06cfe0f..46b18f11c 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -7,9 +7,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -24,7 +24,6 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### - import os import sys import logging @@ -37,6 +36,8 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, check_directory_exists from openlp.core.resources import qInitResources from openlp.core.ui.mainwindow import MainWindow +from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm +from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.exceptionform import ExceptionForm from openlp.core.ui import SplashScreen, ScreenList from openlp.core.utils import AppLocation, LanguageManager, VersionThread @@ -70,12 +71,14 @@ class OpenLP(QtGui.QApplication): The core application class. This class inherits from Qt's QApplication class in order to provide the core of the application. """ - log.info(u'OpenLP Application Loaded') + app_version = None - def _get_version(self): + def get_version(self): """ Load and store current Application Version """ + if self.app_version: + return self.app_version if u'--dev-version' in sys.argv or u'-d' in sys.argv: # If we're running the dev version, let's use bzr to get the version try: @@ -135,30 +138,25 @@ class OpenLP(QtGui.QApplication): if fversion: fversion.close() bits = full_version.split(u'-') - app_version = { + self.app_version = { u'full': full_version, u'version': bits[0], u'build': bits[1] if len(bits) > 1 else None } - if app_version[u'build']: + if self.app_version[u'build']: log.info( u'Openlp version %s build %s', - app_version[u'version'], - app_version[u'build'] + self.app_version[u'version'], + self.app_version[u'build'] ) else: - log.info(u'Openlp version %s' % app_version[u'version']) - return app_version - -# def notify(self, obj, evt): -# #TODO needed for presentation exceptions -# return QtGui.QApplication.notify(self, obj, evt) + log.info(u'Openlp version %s' % self.app_version[u'version']) + return self.app_version def run(self): """ Run the OpenLP application. """ - app_version = self._get_version() # provide a listener for widgets to reqest a screen update. QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_process_events'), self.processEvents) @@ -166,10 +164,15 @@ class OpenLP(QtGui.QApplication): QtCore.SIGNAL(u'cursor_busy'), self.setBusyCursor) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor) - self.setOrganizationName(u'OpenLP') - self.setOrganizationDomain(u'openlp.org') - self.setApplicationName(u'OpenLP') - self.setApplicationVersion(app_version[u'version']) + # Decide how many screens we have and their size + screens = ScreenList(self.desktop()) + # First time checks in settings + has_run_wizard = QtCore.QSettings().value( + u'general/has run wizard', QtCore.QVariant(False)).toBool() + if not has_run_wizard: + if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted: + QtCore.QSettings().setValue(u'general/has run wizard', + QtCore.QVariant(True)) if os.name == u'nt': self.setStyleSheet(application_stylesheet) show_splash = QtCore.QSettings().value( @@ -179,26 +182,21 @@ class OpenLP(QtGui.QApplication): self.splash.show() # make sure Qt really display the splash screen self.processEvents() - screens = ScreenList() - # Decide how many screens we have and their size - for screen in xrange(0, self.desktop().numScreens()): - size = self.desktop().screenGeometry(screen) - screens.add_screen({u'number': screen, - u'size': size, - u'primary': (self.desktop().primaryScreen() == screen)}) - log.info(u'Screen %d found with resolution %s', screen, size) # start the main app window - self.appClipboard = self.clipboard() - self.mainWindow = MainWindow(screens, app_version, self.appClipboard) + self.mainWindow = MainWindow(screens, self.app_version, + self.clipboard()) self.mainWindow.show() if show_splash: # now kill the splashscreen self.splash.finish(self.mainWindow) self.mainWindow.repaint() + self.processEvents() + if not has_run_wizard: + self.mainWindow.firstTime() update_check = QtCore.QSettings().value( u'general/update check', QtCore.QVariant(True)).toBool() if update_check: - VersionThread(self.mainWindow, app_version).start() + VersionThread(self.mainWindow, self.app_version).start() return self.exec_() def hookException(self, exctype, value, traceback): @@ -273,10 +271,20 @@ def main(): qInitResources() # Now create and actually run the application. app = OpenLP(qt_args) - if sys.platform == 'darwin': + app.setOrganizationName(u'OpenLP') + app.setOrganizationDomain(u'openlp.org') + app.setApplicationName(u'OpenLP') + app.setApplicationVersion(app.get_version()[u'version']) + # First time checks in settings + if not QtCore.QSettings().value(u'general/has run wizard', + QtCore.QVariant(False)).toBool(): + if not FirstTimeLanguageForm().exec_(): + # if cancel then stop processing + sys.exit() + if sys.platform == u'darwin': OpenLP.addLibraryPath(QtGui.QApplication.applicationDirPath() + "/qt4_plugins") - #i18n Set Language + # i18n Set Language language = LanguageManager.get_language() appTranslator = LanguageManager.get_translator(language) app.installTranslator(appTranslator) diff --git a/openlp/__init__.py b/openlp/__init__.py index 9c22aab8b..ac3dac24c 100644 --- a/openlp/__init__.py +++ b/openlp/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index 00d8b78c0..1cef928bc 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index dc60a5a65..0d56d1ddd 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -248,9 +248,8 @@ def resize_image(image, width, height, background=QtCore.Qt.black): ``height`` The new image height. - ``background`` + ``background`` The background colour defaults to black. - """ log.debug(u'resize_image - start') if isinstance(image, QtGui.QImage): diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index c92f992c8..42dab1e42 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/displaytags.py b/openlp/core/lib/displaytags.py index fc36bc090..b584af023 100644 --- a/openlp/core/lib/displaytags.py +++ b/openlp/core/lib/displaytags.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/dockwidget.py b/openlp/core/lib/dockwidget.py index efc0a3066..9b4661fee 100644 --- a/openlp/core/lib/dockwidget.py +++ b/openlp/core/lib/dockwidget.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 78b0c6324..a8034fbb6 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 4faf47ddc..67a05c6a1 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 31b41dc0f..4873f4975 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/listwidgetwithdnd.py b/openlp/core/lib/listwidgetwithdnd.py index 5cd8cf9e2..c45b4cc9d 100644 --- a/openlp/core/lib/listwidgetwithdnd.py +++ b/openlp/core/lib/listwidgetwithdnd.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index c44b89534..087c2a1d3 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -220,8 +220,6 @@ class MediaManagerItem(QtGui.QWidget): if self.hasDeleteIcon: toolbar_actions.append([StringContent.Delete, u':/general/general_delete.png', self.onDeleteClick]) - ## Separator Line ## - self.addToolbarSeparator() ## Preview ## toolbar_actions.append([StringContent.Preview, u':/general/general_preview.png', self.onPreviewClick]) @@ -232,6 +230,8 @@ class MediaManagerItem(QtGui.QWidget): toolbar_actions.append([StringContent.Service, u':/general/general_add.png', self.onAddClick]) for action in toolbar_actions: + if action[0] == StringContent.Preview: + self.addToolbarSeparator() self.addToolbarButton( self.plugin.getString(action[0])[u'title'], self.plugin.getString(action[0])[u'tooltip'], @@ -349,11 +349,11 @@ class MediaManagerItem(QtGui.QWidget): Validates whether an image still exists and, if it does, is the thumbnail representation of the image up to date. """ - if not os.path.exists(image): + if not os.path.exists(unicode(image)): return False if os.path.exists(thumb): - imageDate = os.stat(image).st_mtime - thumbDate = os.stat(thumb).st_mtime + imageDate = os.stat(unicode(image)).st_mtime + thumbDate = os.stat(unicode(thumb)).st_mtime # If image has been updated rebuild icon if imageDate > thumbDate: self.iconFromFile(image, thumb) diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py index c1ff30281..5b96bbf00 100644 --- a/openlp/core/lib/plugin.py +++ b/openlp/core/lib/plugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -114,8 +114,8 @@ class Plugin(QtCore.QObject): """ log.info(u'loaded') - def __init__(self, name, version=None, pluginHelpers=None, - mediaItemClass=None, settingsTabClass=None): + def __init__(self, name, pluginHelpers=None, mediaItemClass=None, + settingsTabClass=None, version=None): """ This is the constructor for the plugin object. This provides an easy way for descendent plugins to populate common data. This method *must* @@ -123,7 +123,7 @@ class Plugin(QtCore.QObject): class MyPlugin(Plugin): def __init__(self): - Plugin.__init__(self, u'MyPlugin', u'0.1') + Plugin.__init__(self, u'MyPlugin', version=u'0.1') ``name`` Defaults to *None*. The name of the plugin. @@ -145,8 +145,7 @@ class Plugin(QtCore.QObject): self.textStrings = {} self.setPluginTextStrings() self.nameStrings = self.textStrings[StringContent.Name] - if version: - self.version = version + self.version = version if version else u'1.9.5' self.settingsSection = self.name.lower() self.icon = None self.mediaItemClass = mediaItemClass diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index d2b05ab7c..9289084c6 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -49,16 +49,13 @@ class PluginManager(object): ``plugin_dir`` The directory to search for plugins. """ - log.info(u'Plugin manager initing') + log.info(u'Plugin manager Initialising') if not plugin_dir in sys.path: log.debug(u'Inserting %s into sys.path', plugin_dir) sys.path.insert(0, plugin_dir) self.basepath = os.path.abspath(plugin_dir) log.debug(u'Base path %s ', self.basepath) - self.plugin_helpers = [] self.plugins = [] - # this has to happen after the UI is sorted - # self.find_plugins(plugin_dir) log.info(u'Plugin manager Initialised') def find_plugins(self, plugin_dir, plugin_helpers): @@ -73,7 +70,7 @@ class PluginManager(object): A list of helper objects to pass to the plugins. """ - self.plugin_helpers = plugin_helpers + log.info(u'Finding plugins') startdepth = len(os.path.abspath(plugin_dir).split(os.sep)) log.debug(u'finding plugins in %s at depth %d', unicode(plugin_dir), startdepth) @@ -102,11 +99,11 @@ class PluginManager(object): plugin_objects = [] for p in plugin_classes: try: - plugin = p(self.plugin_helpers) - log.debug(u'Loaded plugin %s with helpers', unicode(p)) + plugin = p(plugin_helpers) + log.debug(u'Loaded plugin %s', unicode(p)) plugin_objects.append(plugin) except TypeError: - log.exception(u'loaded plugin %s has no helpers', unicode(p)) + log.exception(u'Failed to load plugin %s', unicode(p)) plugins_list = sorted(plugin_objects, self.order_by_weight) for plugin in plugins_list: if plugin.checkPreConditions(): @@ -203,6 +200,7 @@ class PluginManager(object): Loop through all the plugins and give them an opportunity to initialise themselves. """ + log.info(u'Initialise Plugins - Started') for plugin in self.plugins: log.info(u'initialising plugins %s in a %s state' % (plugin.name, plugin.isActive())) @@ -211,6 +209,7 @@ class PluginManager(object): log.info(u'Initialisation Complete for %s ' % plugin.name) if not plugin.isActive(): plugin.removeToolboxItem() + log.info(u'Initialise Plugins - Finished') def finalise_plugins(self): """ diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 4df87a4df..0eeae6abd 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index eaf628a34..39c2c3b27 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -69,7 +69,6 @@ class RenderManager(object): self.image_manager = ImageManager() self.display = MainDisplay(self, screens, False) self.display.imageManager = self.image_manager - self.display.setup() self.theme_manager = theme_manager self.renderer = Renderer() self.calculate_default(self.screens.current[u'size']) diff --git a/openlp/core/lib/searchedit.py b/openlp/core/lib/searchedit.py index d2424d00e..4841d76dc 100644 --- a/openlp/core/lib/searchedit.py +++ b/openlp/core/lib/searchedit.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index de4f2fd81..63b9dce00 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -62,7 +62,7 @@ class ItemCapabilities(object): AddIfNewItem = 9 ProvidesOwnDisplay = 10 AllowsDetailedTitleDisplay = 11 - AllowsVarableStartTime = 12 + AllowsVariableStartTime = 12 class ServiceItem(object): @@ -88,8 +88,8 @@ class ServiceItem(object): self.audit = u'' self.items = [] self.iconic_representation = None - self.raw_footer = None - self.foot_text = None + self.raw_footer = [] + self.foot_text = u'' self.theme = None self.service_item_type = None self._raw_frames = [] @@ -162,9 +162,7 @@ class ServiceItem(object): line_break = True if self.is_capable(ItemCapabilities.NoLineBreaks): line_break = False - theme = None - if self.theme: - theme = self.theme + theme = self.theme if self.theme else None self.main, self.footer = \ self.render_manager.set_override_theme(theme, useOverride) self.themedata = self.render_manager.renderer._theme @@ -185,13 +183,13 @@ class ServiceItem(object): else: log.error(u'Invalid value renderer :%s' % self.service_item_type) self.title = clean_tags(self.title) - self.foot_text = None - if self.raw_footer: - for foot in self.raw_footer: - if not self.foot_text: - self.foot_text = foot - else: - self.foot_text = u'%s
%s' % (self.foot_text, foot) + # The footer should never be None, but to be compatible with a few + # nightly builds between 1.9.4 and 1.9.5, we have to correct this to + # avoid tracebacks. + if self.raw_footer is None: + self.raw_footer = [] + self.foot_text = \ + u'
'.join([footer for footer in self.raw_footer if footer]) def add_from_image(self, path, title): """ @@ -204,8 +202,7 @@ class ServiceItem(object): A title for the slide in the service item. """ self.service_item_type = ServiceItemType.Image - self._raw_frames.append( - {u'title': title, u'path': path}) + self._raw_frames.append({u'title': title, u'path': path}) self.render_manager.image_manager.add_image(title, path) self._new_item() @@ -452,3 +449,4 @@ class ServiceItem(object): return end else: return u'%s : %s' % (start, end) + diff --git a/openlp/core/lib/settingsmanager.py b/openlp/core/lib/settingsmanager.py index d09497540..bb83371e6 100644 --- a/openlp/core/lib/settingsmanager.py +++ b/openlp/core/lib/settingsmanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index 4f3748c8d..1c2ad5fe4 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index 493781ccc..4016dcb09 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index ef26ca842..134df7652 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/lib/toolbar.py b/openlp/core/lib/toolbar.py index 37fb67d52..d5d2fa4f8 100644 --- a/openlp/core/lib/toolbar.py +++ b/openlp/core/lib/toolbar.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -48,7 +48,7 @@ class OpenLPToolbar(QtGui.QToolBar): self.icons = {} self.setIconSize(QtCore.QSize(20, 20)) self.actions = {} - log.debug(u'Init done') + log.debug(u'Init done for %s' % parent.__class__.__name__) def addToolbarButton(self, title, icon, tooltip=None, slot=None, checkable=False, shortcut=0, alternate=0, diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index eae4f60ca..da046d99c 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/theme/__init__.py b/openlp/core/theme/__init__.py index 52f7120b1..bd5ba899d 100644 --- a/openlp/core/theme/__init__.py +++ b/openlp/core/theme/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/theme/theme.py b/openlp/core/theme/theme.py index bb6b25a9e..78e9cb7e7 100644 --- a/openlp/core/theme/theme.py +++ b/openlp/core/theme/theme.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 158f7f0cd..a2985c0b8 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -51,6 +51,8 @@ class HideMode(object): Theme = 2 Screen = 3 +from firsttimeform import FirstTimeForm +from firsttimelanguageform import FirstTimeLanguageForm from themeform import ThemeForm from filerenameform import FileRenameForm from starttimeform import StartTimeForm @@ -74,4 +76,4 @@ from thememanager import ThemeManager __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager', - 'ServiceItemEditForm'] + 'ServiceItemEditForm', u'FirstTimeForm'] diff --git a/openlp/core/ui/aboutdialog.py b/openlp/core/ui/aboutdialog.py index 5ba5783ea..33fc53827 100644 --- a/openlp/core/ui/aboutdialog.py +++ b/openlp/core/ui/aboutdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -106,38 +106,86 @@ class Ui_AboutDialog(object): )) self.aboutNotebook.setTabText( self.aboutNotebook.indexOf(self.aboutTab), UiStrings.About) - self.creditsTextEdit.setPlainText(translate('OpenLP.AboutForm', + lead = u'Raoul "superfly" Snyman' + developers = [u'Tim "TRB143" Bentley', u'Jonathan "gushie" Corwin', + u'Michael "cocooncrash" Gorven', + u'Andreas "googol" Preikschat', u'Raoul "superfly" Snyman', + u'Martin "mijiti" Thompson', u'Jon "Meths" Tibble'] + contributors = [u'Scott "sguerrieri" Guerrieri', + u'Matthias "matthub" Hub', u'Meinert "m2j" Jordan', + u'Armin "orangeshirt" K\xf6hler', u'Mattias "mahfiaz" P\xf5ldaru', + u'Christian "crichter" Richter', u'Philip "Phill" Ridout', + u'Jeffrey "whydoubt" Smith', u'Maikel Stuivenberg', + u'Frode "frodus" Woldsund'] + testers = [u'Philip "Phill" Ridout', u'Wesley "wrst" Stout', + u'John "jseagull1" Cegalis (lead)'] + packagers = ['Thomas "tabthorpe" Abthorpe (FreeBSD)', + u'Tim "TRB143" Bentley (Fedora)', + u'Matthias "matthub" Hub (Mac OS X)', + u'Stevan "StevanP" Pettit (Windows)', + u'Raoul "superfly" Snyman (Ubuntu)'] + translators = { + u'af': [u'Johan "nuvolari" Mynhardt'], + u'de': [u'Patrick "madmuffin" Br\xfcckner', + u'Meinert "m2j" Jordan', u'Andreas "googol" Preikschat', + u'Christian "crichter" Richter'], + u'en_GB': [u'Tim "TRB143" Bentley', u'Jonathan "gushie" Corwin'], + u'en_ZA': [u'Raoul "superfly" Snyman'], + u'et': [u'Mattias "mahfiaz" P\xf5ldaru'], + u'fr': [u'Stephan\xe9 "stbrunner" Brunner'], + u'hu': [u'Gyuris Gell\xe9t'], + u'ja': [u'Kunio "Kunio" Nakamaru'], + u'nb': [u'Atle "pendlaren" Weibell', u'Frode "frodus" Woldsund'], + u'nl': [u'Arjen "typovar" van Voorst'], + u'pt_BR': [u'Rafael "rafaellerm" Lerm', u'Gustavo Bim'], + u'ru': [u'Sergey "ratz" Ratz'] + } + documentors = [u'Wesley "wrst" Stout', + u'John "jseagull1" Cegalis (lead)'] + self.creditsTextEdit.setPlainText(unicode(translate('OpenLP.AboutForm', 'Project Lead\n' - ' Raoul "superfly" Snyman\n' + ' %s\n' '\n' 'Developers\n' - ' Tim "TRB143" Bentley\n' - ' Jonathan "gushie" Corwin\n' - ' Michael "cocooncrash" Gorven\n' - ' Scott "sguerrieri" Guerrieri\n' - ' Raoul "superfly" Snyman\n' - ' Martin "mijiti" Thompson\n' - ' Jon "Meths" Tibble\n' + ' %s\n' '\n' 'Contributors\n' - ' Meinert "m2j" Jordan\n' - ' Andreas "googol" Preikschat\n' - ' Christian "crichter" Richter\n' - ' Philip "Phill" Ridout\n' - ' Maikel Stuivenberg\n' - ' Carsten "catini" Tingaard\n' - ' Frode "frodus" Woldsund\n' + ' %s\n' '\n' 'Testers\n' - ' Philip "Phill" Ridout\n' - ' Wesley "wrst" Stout (lead)\n' + ' %s\n' '\n' 'Packagers\n' - ' Thomas "tabthorpe" Abthorpe (FreeBSD)\n' - ' Tim "TRB143" Bentley (Fedora)\n' - ' Michael "cocooncrash" Gorven (Ubuntu)\n' - ' Matthias "matthub" Hub (Mac OS X)\n' - ' Raoul "superfly" Snyman (Windows, Ubuntu)\n' + ' %s\n' + '\n' + 'Translators\n' + ' Afrikaans (af)\n' + ' %s\n' + ' German (de)\n' + ' %s\n' + ' English, United Kingdom (en_GB)\n' + ' %s\n' + ' English, South Africa (en_ZA)\n' + ' %s\n' + ' Estonian (et)\n' + ' %s\n' + ' French (fr)\n' + ' %s\n' + ' Hungarian (hu)\n' + ' %s\n' + ' Japanese (ja)\n' + ' %s\n' + ' Norwegian Bokm\xe5l (nb)\n' + ' %s\n' + ' Dutch (nl)\n' + ' %s\n' + ' Portuguese, Brazil (pt_BR)\n' + ' %s\n' + ' Russian (ru)\n' + ' %s\n' + '\n' + 'Documentation\n' + ' %s\n' '\n' 'Built With\n' ' Python: http://www.python.org/\n' @@ -155,31 +203,42 @@ class Ui_AboutDialog(object): ' God our Father, for sending His Son to die\n' ' on the cross, setting us free from sin. We\n' ' bring this software to you for free because\n' - ' He has set us free.' - )) + ' He has set us free.')) % (lead, u'\n '.join(developers), + u'\n '.join(contributors), u'\n '.join(testers), + u'\n '.join(packagers), u'\n '.join(translators[u'af']), + u'\n '.join(translators[u'de']), + u'\n '.join(translators[u'en_GB']), + u'\n '.join(translators[u'en_ZA']), + u'\n '.join(translators[u'et']), + u'\n '.join(translators[u'fr']), + u'\n '.join(translators[u'hu']), + u'\n '.join(translators[u'ja']), + u'\n '.join(translators[u'nb']), + u'\n '.join(translators[u'nl']), + u'\n '.join(translators[u'pt_BR']), + u'\n '.join(translators[u'ru']), + u'\n '.join(documentors))) self.aboutNotebook.setTabText( self.aboutNotebook.indexOf(self.creditsTab), translate('OpenLP.AboutForm', 'Credits')) - self.licenseTextEdit.setPlainText(translate('OpenLP.AboutForm', + copyright = translate('OpenLP.AboutForm', 'Copyright \xa9 2004-2011 Raoul Snyman\n' 'Portions copyright \xa9 2004-2011 ' 'Tim Bentley, Jonathan Corwin, Michael Gorven, Scott Guerrieri,\n' 'Meinert Jordan, Andreas Preikschat, Christian Richter, Philip\n' - 'Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Carstenn' - 'Tinggaard, Frode Woldsund\n' - '\n' + 'Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Carsten\n' + 'Tinggaard, Frode Woldsund') + licence = translate('OpenLP.AboutForm', 'This program is free software; you can redistribute it and/or ' 'modify it under the terms of the GNU General Public License as ' 'published by the Free Software Foundation; version 2 of the ' - 'License.\n' - '\n' + 'License.') + disclaimer = translate('OpenLP.AboutForm', 'This program is distributed in the hope that it will be useful, ' 'but WITHOUT ANY WARRANTY; without even the implied warranty of ' 'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See below ' - 'for more details.\n' - '\n' - '\n' - 'GNU GENERAL PUBLIC LICENSE\n' + 'for more details.') + gpltext = ('GNU GENERAL PUBLIC LICENSE\n' 'Version 2, June 1991\n' '\n' 'Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 ' @@ -549,7 +608,9 @@ class Ui_AboutDialog(object): 'subroutine library, you may consider it more useful to permit ' 'linking proprietary applications with the library. If this is ' 'what you want to do, use the GNU Lesser General Public License ' - 'instead of this License.')) + 'instead of this License.') + self.licenseTextEdit.setPlainText(u'%s\n\n%s\n\n%s\n\n\n%s' % + (copyright, licence, disclaimer, gpltext)) self.aboutNotebook.setTabText( self.aboutNotebook.indexOf(self.licenseTab), translate('OpenLP.AboutForm', 'License')) diff --git a/openlp/core/ui/aboutform.py b/openlp/core/ui/aboutform.py index a6550b23c..5c26167e3 100644 --- a/openlp/core/ui/aboutform.py +++ b/openlp/core/ui/aboutform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index a8e8b294e..e9ab159ea 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/displaytagdialog.py b/openlp/core/ui/displaytagdialog.py index 2b6441e16..848818e88 100644 --- a/openlp/core/ui/displaytagdialog.py +++ b/openlp/core/ui/displaytagdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -143,11 +143,11 @@ class Ui_DisplayTagDialog(object): self.tagTableWidget.horizontalHeaderItem(0).setText( translate('OpenLP.DisplayTagDialog', 'Description')) self.tagTableWidget.horizontalHeaderItem(1).setText( - translate('OpenLP.DisplayTagDialog', 'Tag id')) + translate('OpenLP.DisplayTagDialog', 'Tag Id')) self.tagTableWidget.horizontalHeaderItem(2).setText( - translate('OpenLP.DisplayTagDialog', 'Start Html')) + translate('OpenLP.DisplayTagDialog', 'Start HTML')) self.tagTableWidget.horizontalHeaderItem(3).setText( - translate('OpenLP.DisplayTagDialog', 'End Html')) + translate('OpenLP.DisplayTagDialog', 'End HTML')) self.tagTableWidget.setColumnWidth(0, 120) self.tagTableWidget.setColumnWidth(1, 40) self.tagTableWidget.setColumnWidth(2, 240) diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/displaytagform.py index e29fe3384..24cd14bd0 100644 --- a/openlp/core/ui/displaytagform.py +++ b/openlp/core/ui/displaytagform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/exceptiondialog.py b/openlp/core/ui/exceptiondialog.py index 770913b01..4aa01f776 100644 --- a/openlp/core/ui/exceptiondialog.py +++ b/openlp/core/ui/exceptiondialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 6fb2d3f84..50cf597ea 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/filerenamedialog.py b/openlp/core/ui/filerenamedialog.py index 30c206d2c..ec0f0e2dd 100644 --- a/openlp/core/ui/filerenamedialog.py +++ b/openlp/core/ui/filerenamedialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/filerenameform.py b/openlp/core/ui/filerenameform.py index 69a1c3f6a..049b68336 100644 --- a/openlp/core/ui/filerenameform.py +++ b/openlp/core/ui/filerenameform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py new file mode 100644 index 000000000..dc1932015 --- /dev/null +++ b/openlp/core/ui/firsttimeform.py @@ -0,0 +1,312 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +import io +import logging +import os +import urllib +from tempfile import gettempdir +from ConfigParser import SafeConfigParser + +from PyQt4 import QtCore, QtGui + +from openlp.core.lib import translate, PluginStatus, Receiver, build_icon, \ + check_directory_exists +from openlp.core.utils import get_web_page, AppLocation +from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage + +log = logging.getLogger(__name__) + +class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): + """ + This is the Theme Import Wizard, which allows easy creation and editing of + OpenLP themes. + """ + log.info(u'ThemeWizardForm loaded') + + def __init__(self, screens, parent=None): + QtGui.QWizard.__init__(self, parent) + self.setupUi(self) + self.screens = screens + # check to see if we have web access + self.web = u'http://openlp.org/files/frw/' + self.config = SafeConfigParser() + self.webAccess = get_web_page(u'%s%s' % (self.web, u'download.cfg')) + if self.webAccess: + files = self.webAccess.read() + self.config.readfp(io.BytesIO(files)) + self.updateScreenListCombo() + self.downloading = unicode(translate('OpenLP.FirstTimeWizard', + 'Downloading %s...')) + QtCore.QObject.connect(self, + QtCore.SIGNAL(u'currentIdChanged(int)'), self.onCurrentIdChanged) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'config_screen_changed'), self.updateScreenListCombo) + + def exec_(self, edit=False): + """ + Run the wizard. + """ + self.setDefaults() + return QtGui.QWizard.exec_(self) + + def setDefaults(self): + """ + Set up display at start of theme edit. + """ + self.restart() + check_directory_exists(os.path.join(gettempdir(), u'openlp')) + # Sort out internet access for downloads + if self.webAccess: + songs = self.config.get(u'songs', u'languages') + songs = songs.split(u',') + for song in songs: + title = unicode(self.config.get( + u'songs_%s' % song, u'title'), u'utf8') + filename = unicode(self.config.get( + u'songs_%s' % song, u'filename'), u'utf8') + item = QtGui.QListWidgetItem(title, self.songsListWidget) + item.setData(QtCore.Qt.UserRole, QtCore.QVariant(filename)) + item.setCheckState(QtCore.Qt.Unchecked) + item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) + bible_languages = self.config.get(u'bibles', u'languages') + bible_languages = bible_languages.split(u',') + for lang in bible_languages: + language = unicode(self.config.get( + u'bibles_%s' % lang, u'title'), u'utf8') + langItem = QtGui.QTreeWidgetItem( + self.biblesTreeWidget, QtCore.QStringList(language)) + bibles = self.config.get(u'bibles_%s' % lang, u'translations') + bibles = bibles.split(u',') + for bible in bibles: + title = unicode(self.config.get( + u'bible_%s' % bible, u'title'), u'utf8') + filename = unicode(self.config.get( + u'bible_%s' % bible, u'filename')) + item = QtGui.QTreeWidgetItem( + langItem, QtCore.QStringList(title)) + item.setData(0, QtCore.Qt.UserRole, + QtCore.QVariant(filename)) + item.setCheckState(0, QtCore.Qt.Unchecked) + item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) + self.biblesTreeWidget.expandAll() + themes = self.config.get(u'themes', u'files') + themes = themes.split(u',') + for theme in themes: + title = self.config.get(u'theme_%s' % theme, u'title') + filename = self.config.get(u'theme_%s' % theme, u'filename') + screenshot = self.config.get(u'theme_%s' % theme, u'screenshot') + urllib.urlretrieve(u'%s/%s' % (self.web, screenshot), + os.path.join(gettempdir(), u'openlp', screenshot)) + item = QtGui.QListWidgetItem(title, self.themesListWidget) + item.setData(QtCore.Qt.UserRole, + QtCore.QVariant(filename)) + item.setIcon(build_icon( + os.path.join(gettempdir(), u'openlp', screenshot))) + item.setCheckState(QtCore.Qt.Unchecked) + item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) + + def nextId(self): + """ + Determine the next page in the Wizard to go to. + """ + if self.currentId() == FirstTimePage.Plugins: + if not self.webAccess: + return FirstTimePage.NoInternet + else: + return FirstTimePage.Songs + elif self.currentId() == FirstTimePage.Progress: + return -1 + else: + return self.currentId() + 1 + + def onCurrentIdChanged(self, pageId): + """ + Detects Page changes and updates as approprate. + """ + if pageId == FirstTimePage.NoInternet: + self.finishButton.setVisible(True) + self.finishButton.setEnabled(True) + self.nextButton.setVisible(False) + elif pageId == FirstTimePage.Defaults: + self.themeComboBox.clear() + for iter in xrange(self.themesListWidget.count()): + item = self.themesListWidget.item(iter) + if item.checkState() == QtCore.Qt.Checked: + self.themeComboBox.addItem(item.text()) + elif pageId == FirstTimePage.Progress: + self._preWizard() + self._performWizard() + self._postWizard() + + def updateScreenListCombo(self): + """ + The user changed screen resolution or enabled/disabled more screens, so + we need to update the combo box. + """ + self.displayComboBox.clear() + self.displayComboBox.addItems(self.screens.get_screen_list()) + self.displayComboBox.setCurrentIndex(self.displayComboBox.count() - 1) + + def _getFileSize(self, url): + site = urllib.urlopen(url) + meta = site.info() + return int(meta.getheaders("Content-Length")[0]) + + def _downloadProgress(self, count, block_size, total_size): + increment = (count * block_size) - self.previous_size + self._incrementProgressBar(None, increment) + self.previous_size = count * block_size + + def _incrementProgressBar(self, status_text, increment=1): + """ + Update the wizard progress page. + + ``status_text`` + Current status information to display. + + ``increment`` + The value to increment the progress bar by. + """ + if status_text: + self.progressLabel.setText(status_text) + if increment > 0: + self.progressBar.setValue(self.progressBar.value() + increment) + Receiver.send_message(u'openlp_process_events') + + def _preWizard(self): + """ + Prepare the UI for the process. + """ + # We start on 2 for plugins status setting plus a "finished" point. + max_progress = 2 + # Loop through the songs list and increase for each selected item + for i in xrange(self.songsListWidget.count()): + item = self.songsListWidget.item(i) + if item.checkState() == QtCore.Qt.Checked: + filename = item.data(QtCore.Qt.UserRole).toString() + size = self._getFileSize(u'%s%s' % (self.web, filename)) + max_progress += size + # Loop through the Bibles list and increase for each selected item + iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget) + while iterator.value(): + item = iterator.value() + if item.parent() and item.checkState(0) == QtCore.Qt.Checked: + filename = item.data(0, QtCore.Qt.UserRole).toString() + size = self._getFileSize(u'%s%s' % (self.web, filename)) + max_progress += size + iterator += 1 + # Loop through the themes list and increase for each selected item + for i in xrange(self.themesListWidget.count()): + item = self.themesListWidget.item(i) + if item.checkState() == QtCore.Qt.Checked: + filename = item.data(QtCore.Qt.UserRole).toString() + size = self._getFileSize(u'%s%s' % (self.web, filename)) + max_progress += size + self.finishButton.setVisible(False) + self.progressBar.setValue(0) + self.progressBar.setMinimum(0) + self.progressBar.setMaximum(max_progress) + + def _postWizard(self): + """ + Clean up the UI after the process has finished. + """ + self.progressBar.setValue(self.progressBar.maximum()) + self.finishButton.setVisible(True) + self.finishButton.setEnabled(True) + self.cancelButton.setVisible(False) + self.nextButton.setVisible(False) + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Download complete. Click the finish button to start OpenLP.')) + Receiver.send_message(u'openlp_process_events') + + def _performWizard(self): + """ + Run the tasks in the wizard. + """ + # Set plugin states + self._incrementProgressBar(translate('OpenLP.FirstTimeWizard', + 'Enabling selected plugins...')) + self._setPluginStatus(self.songsCheckBox, u'songs/status') + self._setPluginStatus(self.bibleCheckBox, u'bibles/status') + self._setPluginStatus(self.presentationCheckBox, + u'presentations/status') + self._setPluginStatus(self.imageCheckBox, u'images/status') + self._setPluginStatus(self.mediaCheckBox, u'media/status') + self._setPluginStatus(self.remoteCheckBox, u'remotes/status') + self._setPluginStatus(self.customCheckBox, u'custom/status') + self._setPluginStatus(self.songUsageCheckBox, u'songusage/status') + self._setPluginStatus(self.alertCheckBox, u'alerts/status') + # Build directories for downloads + songs_destination = os.path.join(unicode(gettempdir()), u'openlp') + bibles_destination = AppLocation.get_section_data_path(u'bibles') + themes_destination = AppLocation.get_section_data_path(u'themes') + # Download songs + for i in xrange(self.songsListWidget.count()): + item = self.songsListWidget.item(i) + if item.checkState() == QtCore.Qt.Checked: + filename = item.data(QtCore.Qt.UserRole).toString() + self._incrementProgressBar(self.downloading % filename, 0) + self.previous_size = 0 + destination = os.path.join(songs_destination, unicode(filename)) + urllib.urlretrieve(u'%s%s' % (self.web, filename), destination, + self._downloadProgress) + # Download Bibles + bibles_iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget) + while bibles_iterator.value(): + item = bibles_iterator.value() + if item.parent() and item.checkState(0) == QtCore.Qt.Checked: + bible = unicode(item.data(0, QtCore.Qt.UserRole).toString()) + self._incrementProgressBar(self.downloading % bible, 0) + self.previous_size = 0 + urllib.urlretrieve(u'%s%s' % (self.web, bible), + os.path.join(bibles_destination, bible), + self._downloadProgress) + bibles_iterator += 1 + # Download themes + for i in xrange(self.themesListWidget.count()): + item = self.themesListWidget.item(i) + if item.checkState() == QtCore.Qt.Checked: + theme = unicode(item.data(QtCore.Qt.UserRole).toString()) + self._incrementProgressBar(self.downloading % theme, 0) + self.previous_size = 0 + urllib.urlretrieve(u'%s%s' % (self.web, theme), + os.path.join(themes_destination, theme), + self._downloadProgress) + # Set Default Display + if self.displayComboBox.currentIndex() != -1: + QtCore.QSettings().setValue(u'General/monitor', + QtCore.QVariant(self.displayComboBox.currentIndex())) + # Set Global Theme + if self.themeComboBox.currentIndex() != -1: + QtCore.QSettings().setValue(u'themes/global theme', + QtCore.QVariant(self.themeComboBox.currentText())) + + def _setPluginStatus(self, field, tag): + status = PluginStatus.Active if field.checkState() \ + == QtCore.Qt.Checked else PluginStatus.Inactive + QtCore.QSettings().setValue(tag, QtCore.QVariant(status)) diff --git a/openlp/core/ui/firsttimelanguagedialog.py b/openlp/core/ui/firsttimelanguagedialog.py new file mode 100644 index 000000000..bdc03048a --- /dev/null +++ b/openlp/core/ui/firsttimelanguagedialog.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +from PyQt4 import QtCore, QtGui + +from openlp.core.lib import translate +from openlp.core.lib.ui import create_accept_reject_button_box + +class Ui_FirstTimeLanguageDialog(object): + def setupUi(self, languageDialog): + languageDialog.setObjectName(u'languageDialog') + languageDialog.resize(300, 50) + self.dialogLayout = QtGui.QVBoxLayout(languageDialog) + self.dialogLayout.setContentsMargins(8, 8, 8, 8) + self.dialogLayout.setSpacing(8) + self.dialogLayout.setObjectName(u'dialogLayout') + self.infoLabel = QtGui.QLabel(languageDialog) + self.infoLabel.setObjectName(u'infoLabel') + self.dialogLayout.addWidget(self.infoLabel) + self.languageLayout = QtGui.QHBoxLayout() + self.languageLayout.setObjectName(u'languageLayout') + self.languageLabel = QtGui.QLabel(languageDialog) + self.languageLabel.setObjectName(u'languageLabel') + self.languageLayout.addWidget(self.languageLabel) + self.languageComboBox = QtGui.QComboBox(languageDialog) + self.languageComboBox.setSizeAdjustPolicy( + QtGui.QComboBox.AdjustToContents) + self.languageComboBox.setObjectName("languageComboBox") + self.languageLayout.addWidget(self.languageComboBox) + self.dialogLayout.addLayout(self.languageLayout) + self.buttonBox = create_accept_reject_button_box(languageDialog, True) + self.dialogLayout.addWidget(self.buttonBox) + + self.retranslateUi(languageDialog) + self.setMaximumHeight(self.sizeHint().height()) + QtCore.QMetaObject.connectSlotsByName(languageDialog) + + def retranslateUi(self, languageDialog): + self.setWindowTitle(translate('OpenLP.FirstTimeLanguageForm', + 'Select Translation')) + self.infoLabel.setText(translate('OpenLP.FirstTimeLanguageForm', + 'Choose the translation you\'d like to use in OpenLP.')) + self.languageLabel.setText(translate('OpenLP.FirstTimeLanguageForm', + 'Translation:')) diff --git a/openlp/core/ui/firsttimelanguageform.py b/openlp/core/ui/firsttimelanguageform.py new file mode 100644 index 000000000..f6ffafb8f --- /dev/null +++ b/openlp/core/ui/firsttimelanguageform.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +from PyQt4 import QtGui + +from openlp.core.utils import LanguageManager +from firsttimelanguagedialog import Ui_FirstTimeLanguageDialog + +class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog): + """ + The exception dialog + """ + def __init__(self, parent=None): + QtGui.QDialog.__init__(self, parent) + self.setupUi(self) + self.qmList = LanguageManager.get_qm_list() + self.languageComboBox.addItem(u'Autodetect') + for key in sorted(self.qmList.keys()): + self.languageComboBox.addItem(key) + + def exec_(self): + """ + Run the Dialog with correct heading. + """ + return QtGui.QDialog.exec_(self) + + def accept(self): + # It's the first row so must be Automatic + if self.languageComboBox.currentIndex() == 0: + LanguageManager.auto_language = True + LanguageManager.set_language(False, False) + else: + LanguageManager.auto_language = False + action = QtGui.QAction(None) + action.setObjectName(unicode(self.languageComboBox.currentText())) + LanguageManager.set_language(action, False) + return QtGui.QDialog.accept(self) + + def reject(self): + LanguageManager.auto_language = True + LanguageManager.set_language(False, False) + return QtGui.QDialog.reject(self) diff --git a/openlp/core/ui/firsttimewizard.py b/openlp/core/ui/firsttimewizard.py new file mode 100644 index 000000000..c6d36d741 --- /dev/null +++ b/openlp/core/ui/firsttimewizard.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +from PyQt4 import QtCore, QtGui + +from openlp.core.lib import translate +from openlp.core.lib.ui import add_welcome_page + +class FirstTimePage(object): + Welcome = 0 + Plugins = 1 + NoInternet = 2 + Songs = 3 + Bibles = 4 + Themes = 5 + Defaults = 6 + Progress = 7 + + +class Ui_FirstTimeWizard(object): + def setupUi(self, FirstTimeWizard): + FirstTimeWizard.setObjectName(u'FirstTimeWizard') + FirstTimeWizard.resize(550, 386) + FirstTimeWizard.setModal(True) + FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle) + FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages| + QtGui.QWizard.NoBackButtonOnStartPage | + QtGui.QWizard.NoBackButtonOnLastPage) + self.finishButton = self.button(QtGui.QWizard.FinishButton) + self.cancelButton = self.button(QtGui.QWizard.CancelButton) + self.nextButton = self.button(QtGui.QWizard.NextButton) + self.backButton = self.button(QtGui.QWizard.BackButton) + add_welcome_page(FirstTimeWizard, u':/wizards/wizard_firsttime.bmp') + # The plugins page + self.pluginPage = QtGui.QWizardPage() + self.pluginPage.setObjectName(u'pluginPage') + self.pluginLayout = QtGui.QVBoxLayout(self.pluginPage) + self.pluginLayout.setContentsMargins(40, 15, 40, 0) + self.pluginLayout.setObjectName(u'pluginLayout') + self.songsCheckBox = QtGui.QCheckBox(self.pluginPage) + self.songsCheckBox.setChecked(True) + self.songsCheckBox.setObjectName(u'songsCheckBox') + self.pluginLayout.addWidget(self.songsCheckBox) + self.customCheckBox = QtGui.QCheckBox(self.pluginPage) + self.customCheckBox.setChecked(True) + self.customCheckBox.setObjectName(u'customCheckBox') + self.pluginLayout.addWidget(self.customCheckBox) + self.bibleCheckBox = QtGui.QCheckBox(self.pluginPage) + self.bibleCheckBox.setChecked(True) + self.bibleCheckBox.setObjectName(u'bibleCheckBox') + self.pluginLayout.addWidget(self.bibleCheckBox) + self.imageCheckBox = QtGui.QCheckBox(self.pluginPage) + self.imageCheckBox.setChecked(True) + self.imageCheckBox.setObjectName(u'imageCheckBox') + self.pluginLayout.addWidget(self.imageCheckBox) + self.presentationCheckBox = QtGui.QCheckBox(self.pluginPage) + self.presentationCheckBox.setChecked(True) + self.presentationCheckBox.setObjectName(u'presentationCheckBox') + self.pluginLayout.addWidget(self.presentationCheckBox) + self.mediaCheckBox = QtGui.QCheckBox(self.pluginPage) + self.mediaCheckBox.setChecked(True) + self.mediaCheckBox.setObjectName(u'mediaCheckBox') + self.pluginLayout.addWidget(self.mediaCheckBox) + self.remoteCheckBox = QtGui.QCheckBox(self.pluginPage) + self.remoteCheckBox.setObjectName(u'remoteCheckBox') + self.pluginLayout.addWidget(self.remoteCheckBox) + self.songUsageCheckBox = QtGui.QCheckBox(self.pluginPage) + self.songUsageCheckBox.setChecked(True) + self.songUsageCheckBox.setObjectName(u'songUsageCheckBox') + self.pluginLayout.addWidget(self.songUsageCheckBox) + self.alertCheckBox = QtGui.QCheckBox(self.pluginPage) + self.alertCheckBox.setChecked(True) + self.alertCheckBox.setObjectName(u'alertCheckBox') + self.pluginLayout.addWidget(self.alertCheckBox) + FirstTimeWizard.setPage(FirstTimePage.Plugins, self.pluginPage) + # The "you don't have an internet connection" page. + self.noInternetPage = QtGui.QWizardPage() + self.noInternetPage.setObjectName(u'noInternetPage') + self.noInternetLayout = QtGui.QVBoxLayout(self.noInternetPage) + self.noInternetLayout.setContentsMargins(50, 30, 50, 40) + self.noInternetLayout.setObjectName(u'noInternetLayout') + self.noInternetLabel = QtGui.QLabel(self.noInternetPage) + self.noInternetLabel.setWordWrap(True) + self.noInternetLabel.setObjectName(u'noInternetLabel') + self.noInternetLayout.addWidget(self.noInternetLabel) + FirstTimeWizard.setPage(FirstTimePage.NoInternet, self.noInternetPage) + # The song samples page + self.songsPage = QtGui.QWizardPage() + self.songsPage.setObjectName(u'songsPage') + self.songsLayout = QtGui.QVBoxLayout(self.songsPage) + self.songsLayout.setContentsMargins(50, 20, 50, 20) + self.songsLayout.setObjectName(u'songsLayout') + self.songsListWidget = QtGui.QListWidget(self.songsPage) + self.songsListWidget.setAlternatingRowColors(True) + self.songsListWidget.setObjectName(u'songsListWidget') + self.songsLayout.addWidget(self.songsListWidget) + FirstTimeWizard.setPage(FirstTimePage.Songs, self.songsPage) + # The Bible samples page + self.biblesPage = QtGui.QWizardPage() + self.biblesPage.setObjectName(u'biblesPage') + self.biblesLayout = QtGui.QVBoxLayout(self.biblesPage) + self.biblesLayout.setContentsMargins(50, 20, 50, 20) + self.biblesLayout.setObjectName(u'biblesLayout') + self.biblesTreeWidget = QtGui.QTreeWidget(self.biblesPage) + self.biblesTreeWidget.setAlternatingRowColors(True) + self.biblesTreeWidget.header().setVisible(False) + self.biblesTreeWidget.setObjectName(u'biblesTreeWidget') + self.biblesLayout.addWidget(self.biblesTreeWidget) + FirstTimeWizard.setPage(FirstTimePage.Bibles, self.biblesPage) + # The theme samples page + self.themesPage = QtGui.QWizardPage() + self.themesPage.setObjectName(u'themesPage') + self.themesLayout = QtGui.QVBoxLayout(self.themesPage) + self.themesLayout.setContentsMargins(20, 50, 20, 60) + self.themesLayout.setObjectName(u'themesLayout') + self.themesListWidget = QtGui.QListWidget(self.themesPage) + self.themesListWidget.setViewMode(QtGui.QListView.IconMode) + self.themesListWidget.setMovement(QtGui.QListView.Static) + self.themesListWidget.setFlow(QtGui.QListView.LeftToRight) + self.themesListWidget.setSpacing(4) + self.themesListWidget.setUniformItemSizes(True) + self.themesListWidget.setIconSize(QtCore.QSize(133, 100)) + self.themesListWidget.setWrapping(False) + self.themesListWidget.setObjectName(u'themesListWidget') + self.themesLayout.addWidget(self.themesListWidget) + FirstTimeWizard.setPage(FirstTimePage.Themes, self.themesPage) + # the default settings page + self.defaultsPage = QtGui.QWizardPage() + self.defaultsPage.setObjectName(u'defaultsPage') + self.defaultsLayout = QtGui.QFormLayout(self.defaultsPage) + self.defaultsLayout.setContentsMargins(50, 20, 50, 20) + self.defaultsLayout.setObjectName(u'defaultsLayout') + self.displayLabel = QtGui.QLabel(self.defaultsPage) + self.displayLabel.setObjectName(u'displayLabel') + self.displayComboBox = QtGui.QComboBox(self.defaultsPage) + self.displayComboBox.setEditable(False) + self.displayComboBox.setInsertPolicy(QtGui.QComboBox.NoInsert) + self.displayComboBox.setObjectName(u'displayComboBox') + self.defaultsLayout.addRow(self.displayLabel, self.displayComboBox) + self.themeLabel = QtGui.QLabel(self.defaultsPage) + self.themeLabel.setObjectName(u'themeLabel') + self.themeComboBox = QtGui.QComboBox(self.defaultsPage) + self.themeComboBox.setEditable(False) + self.themeComboBox.setInsertPolicy(QtGui.QComboBox.NoInsert) + self.themeComboBox.setSizeAdjustPolicy( + QtGui.QComboBox.AdjustToContents) + self.themeComboBox.setObjectName(u'themeComboBox') + self.defaultsLayout.addRow(self.themeLabel, self.themeComboBox) + FirstTimeWizard.setPage(FirstTimePage.Defaults, self.defaultsPage) + # Progress page + self.progressPage = QtGui.QWizardPage() + self.progressPage.setObjectName(u'progressPage') + self.progressLayout = QtGui.QVBoxLayout(self.progressPage) + self.progressLayout.setMargin(48) + self.progressLayout.setObjectName(u'progressLayout') + self.progressLabel = QtGui.QLabel(self.progressPage) + self.progressLabel.setObjectName(u'progressLabel') + self.progressLayout.addWidget(self.progressLabel) + self.progressBar = QtGui.QProgressBar(self.progressPage) + self.progressBar.setObjectName(u'progressBar') + self.progressLayout.addWidget(self.progressBar) + FirstTimeWizard.setPage(FirstTimePage.Progress, self.progressPage) + + self.retranslateUi(FirstTimeWizard) + QtCore.QMetaObject.connectSlotsByName(FirstTimeWizard) + + def retranslateUi(self, FirstTimeWizard): + FirstTimeWizard.setWindowTitle(translate( + 'OpenLP.FirstTimeWizard', 'First Time Wizard')) + self.titleLabel.setText( + u'%s' % \ + translate('OpenLP.FirstTimeWizard', + 'Welcome to the First Time Wizard')) + self.informationLabel.setText(translate('OpenLP.FirstTimeWizard', + 'This wizard will help you to configure OpenLP for initial use.' + ' Click the next button below to start the process of selection ' + 'your initial options. ')) + self.pluginPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'Activate required Plugins')) + self.pluginPage.setSubTitle(translate('OpenLP.FirstTimeWizard', + 'Select the Plugins you wish to use. ')) + self.songsCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Songs')) + self.customCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Custom Text')) + self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible')) + self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Images')) + self.presentationCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Presentations')) + self.mediaCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Media (Audio and Video)')) + self.remoteCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Allow remote access')) + self.songUsageCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Monitor Song Usage')) + self.alertCheckBox.setText(translate('OpenLP.FirstTimeWizard', + 'Allow Alerts')) + self.noInternetPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'No Internet Connection')) + self.noInternetPage.setSubTitle(translate( + 'OpenLP.FirstTimeWizard', + 'Unable to detect an Internet connection.')) + self.noInternetLabel.setText(translate('OpenLP.FirstTimeWizard', + 'No Internet connection was found. The First Time Wizard needs an ' + 'Internet connection in order to be able to download sample ' + 'songs, Bibles and themes.\n\nTo re-run the First Time Wizard and ' + 'import this sample data at a later stage, press the cancel ' + 'button now, check your Internet connection, and restart OpenLP.' + '\n\nTo cancel the First Time Wizard completely, press the finish ' + 'button now.')) + self.songsPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'Sample Songs')) + self.songsPage.setSubTitle(translate('OpenLP.FirstTimeWizard', + 'Select and download public domain songs.')) + self.biblesPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'Sample Bibles')) + self.biblesPage.setSubTitle(translate('OpenLP.FirstTimeWizard', + 'Select and download free Bibles.')) + self.themesPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'Sample Themes')) + self.themesPage.setSubTitle(translate('OpenLP.FirstTimeWizard', + 'Select and download sample themes.')) + self.defaultsPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'Default Settings')) + self.defaultsPage.setSubTitle(translate('OpenLP.FirstTimeWizard', + 'Set up default settings to be used by OpenLP.')) + self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard', + 'Setting Up And Importing')) + self.progressPage.setSubTitle(translate('OpenLP.FirstTimeWizard', + 'Please wait while OpenLP is set up and your data is imported.')) + self.displayLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Default output display:')) + self.themeLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Select default theme:')) + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Starting configuration process...')) diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index 4eacc5959..29d6f8aad 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -32,27 +32,6 @@ from openlp.core.lib.ui import UiStrings log = logging.getLogger(__name__) -class ValidEdit(QtGui.QLineEdit): - """ - Only allow numeric characters to be edited - """ - def __init__(self, parent): - """ - Set up Override and Validator - """ - QtGui.QLineEdit.__init__(self, parent) - self.setValidator(QtGui.QIntValidator(0, 9999, self)) - - def validText(self): - """ - Only return Integers. Space is 0 - """ - if self.text().isEmpty(): - return QtCore.QString(u'0') - else: - return self.text() - - class GeneralTab(SettingsTab): """ GeneralTab is the general settings tab in the settings dialog. @@ -164,30 +143,6 @@ class GeneralTab(SettingsTab): self.displayGroupBox.setObjectName(u'displayGroupBox') self.displayLayout = QtGui.QGridLayout(self.displayGroupBox) self.displayLayout.setObjectName(u'displayLayout') - self.currentXLabel = QtGui.QLabel(self.displayGroupBox) - self.currentXLabel.setObjectName(u'currentXLabel') - self.displayLayout.addWidget(self.currentXLabel, 0, 0) - self.currentXValueLabel = QtGui.QLabel(self.displayGroupBox) - self.currentXValueLabel.setObjectName(u'currentXValueLabel') - self.displayLayout.addWidget(self.currentXValueLabel, 1, 0) - self.currentYLabel = QtGui.QLabel(self.displayGroupBox) - self.currentYLabel.setObjectName(u'currentYLabel') - self.displayLayout.addWidget(self.currentYLabel, 0, 1) - self.currentYValueLabel = QtGui.QLabel(self.displayGroupBox) - self.currentYValueLabel.setObjectName(u'currentYValueLabel') - self.displayLayout.addWidget(self.currentYValueLabel, 1, 1) - self.currentWidthLabel = QtGui.QLabel(self.displayGroupBox) - self.currentWidthLabel.setObjectName(u'currentWidthLabel') - self.displayLayout.addWidget(self.currentWidthLabel, 0, 2) - self.currentWidthValueLabel = QtGui.QLabel(self.displayGroupBox) - self.currentWidthValueLabel.setObjectName(u'currentWidthValueLabel') - self.displayLayout.addWidget(self.currentWidthValueLabel, 1, 2) - self.currentHeightLabel = QtGui.QLabel(self.displayGroupBox) - self.currentHeightLabel.setObjectName(u'currentHeightLabel') - self.displayLayout.addWidget(self.currentHeightLabel, 0, 3) - self.currentHeightValueLabel = QtGui.QLabel(self.displayGroupBox) - self.currentHeightValueLabel.setObjectName(u'Height') - self.displayLayout.addWidget(self.currentHeightValueLabel, 1, 3) self.overrideCheckBox = QtGui.QCheckBox(self.displayGroupBox) self.overrideCheckBox.setObjectName(u'overrideCheckBox') self.displayLayout.addWidget(self.overrideCheckBox, 2, 0, 1, 4) @@ -196,26 +151,30 @@ class GeneralTab(SettingsTab): self.customXLabel = QtGui.QLabel(self.displayGroupBox) self.customXLabel.setObjectName(u'customXLabel') self.displayLayout.addWidget(self.customXLabel, 3, 0) - self.customXValueEdit = ValidEdit(self.displayGroupBox) + self.customXValueEdit = QtGui.QSpinBox(self.displayGroupBox) self.customXValueEdit.setObjectName(u'customXValueEdit') + self.customXValueEdit.setMaximum(9999) self.displayLayout.addWidget(self.customXValueEdit, 4, 0) self.customYLabel = QtGui.QLabel(self.displayGroupBox) self.customYLabel.setObjectName(u'customYLabel') self.displayLayout.addWidget(self.customYLabel, 3, 1) - self.customYValueEdit = ValidEdit(self.displayGroupBox) + self.customYValueEdit = QtGui.QSpinBox(self.displayGroupBox) self.customYValueEdit.setObjectName(u'customYValueEdit') + self.customYValueEdit.setMaximum(9999) self.displayLayout.addWidget(self.customYValueEdit, 4, 1) self.customWidthLabel = QtGui.QLabel(self.displayGroupBox) self.customWidthLabel.setObjectName(u'customWidthLabel') self.displayLayout.addWidget(self.customWidthLabel, 3, 2) - self.customWidthValueEdit = ValidEdit(self.displayGroupBox) + self.customWidthValueEdit = QtGui.QSpinBox(self.displayGroupBox) self.customWidthValueEdit.setObjectName(u'customWidthValueEdit') + self.customWidthValueEdit.setMaximum(9999) self.displayLayout.addWidget(self.customWidthValueEdit, 4, 2) self.customHeightLabel = QtGui.QLabel(self.displayGroupBox) self.customHeightLabel.setObjectName(u'customHeightLabel') self.displayLayout.addWidget(self.customHeightLabel, 3, 3) - self.customHeightValueEdit = ValidEdit(self.displayGroupBox) + self.customHeightValueEdit = QtGui.QSpinBox(self.displayGroupBox) self.customHeightValueEdit.setObjectName(u'customHeightValueEdit') + self.customHeightValueEdit.setMaximum(9999) self.displayLayout.addWidget(self.customHeightValueEdit, 4, 3) self.rightLayout.addWidget(self.displayGroupBox) self.rightLayout.addStretch() @@ -223,17 +182,22 @@ class GeneralTab(SettingsTab): QtCore.QObject.connect(self.overrideCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.onOverrideCheckBoxToggled) QtCore.QObject.connect(self.customHeightValueEdit, - QtCore.SIGNAL(u'textEdited(const QString&)'), - self.onDisplayPositionChanged) + QtCore.SIGNAL(u'valueChanged(int)'), self.onDisplayPositionChanged) QtCore.QObject.connect(self.customWidthValueEdit, - QtCore.SIGNAL(u'textEdited(const QString&)'), - self.onDisplayPositionChanged) + QtCore.SIGNAL(u'valueChanged(int)'), self.onDisplayPositionChanged) QtCore.QObject.connect(self.customYValueEdit, - QtCore.SIGNAL(u'textEdited(const QString&)'), - self.onDisplayPositionChanged) + QtCore.SIGNAL(u'valueChanged(int)'), self.onDisplayPositionChanged) QtCore.QObject.connect(self.customXValueEdit, - QtCore.SIGNAL(u'textEdited(const QString&)'), - self.onDisplayPositionChanged) + QtCore.SIGNAL(u'valueChanged(int)'), self.onDisplayPositionChanged) + # Reload the tab, as the screen resolution/count may have changed. + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'config_screen_changed'), self.load) + # Remove for now + self.usernameLabel.setVisible(False) + self.usernameEdit.setVisible(False) + self.passwordLabel.setVisible(False) + self.passwordEdit.setVisible(False) + def retranslateUi(self): """ @@ -264,8 +228,7 @@ class GeneralTab(SettingsTab): 'Automatically preview next item in service')) self.timeoutLabel.setText(translate('OpenLP.GeneralTab', 'Slide loop delay:')) - self.timeoutSpinBox.setSuffix( - translate('OpenLP.GeneralTab', ' sec')) + self.timeoutSpinBox.setSuffix(translate('OpenLP.GeneralTab', ' sec')) self.ccliGroupBox.setTitle( translate('OpenLP.GeneralTab', 'CCLI Details')) self.numberLabel.setText(UiStrings.CCLINumberLabel) @@ -276,22 +239,11 @@ class GeneralTab(SettingsTab): # Moved from display tab self.displayGroupBox.setTitle( translate('OpenLP.GeneralTab', 'Display Position')) - self.currentXLabel.setText(translate('OpenLP.GeneralTab', 'X')) - self.currentXValueLabel.setText(u'0') - self.currentYLabel.setText(translate('OpenLP.GeneralTab', 'Y')) - self.currentYValueLabel.setText(u'0') - self.currentHeightLabel.setText( - translate('OpenLP.GeneralTab', 'Height')) - self.currentHeightValueLabel.setText(u'0') - self.currentWidthLabel.setText( - translate('OpenLP.GeneralTab', 'Width')) - self.currentWidthValueLabel.setText(u'0') self.overrideCheckBox.setText(translate('OpenLP.GeneralTab', 'Override display position')) self.customXLabel.setText(translate('OpenLP.GeneralTab', 'X')) self.customYLabel.setText(translate('OpenLP.GeneralTab', 'Y')) - self.customHeightLabel.setText( - translate('OpenLP.GeneralTab', 'Height')) + self.customHeightLabel.setText(translate('OpenLP.GeneralTab', 'Height')) self.customWidthLabel.setText(translate('OpenLP.GeneralTab', 'Width')) def load(self): @@ -300,13 +252,8 @@ class GeneralTab(SettingsTab): """ settings = QtCore.QSettings() settings.beginGroup(self.settingsSection) - for screen in self.screens.screen_list: - screen_name = u'%s %d' % (translate('OpenLP.GeneralTab', 'Screen'), - screen[u'number'] + 1) - if screen[u'primary']: - screen_name = u'%s (%s)' % (screen_name, - translate('OpenLP.GeneralTab', 'primary')) - self.monitorComboBox.addItem(screen_name) + self.monitorComboBox.clear() + self.monitorComboBox.addItems(self.screens.get_screen_list()) self.numberEdit.setText(unicode(settings.value( u'ccli number', QtCore.QVariant(u'')).toString())) self.usernameEdit.setText(unicode(settings.value( @@ -329,26 +276,16 @@ class GeneralTab(SettingsTab): QtCore.QVariant(False)).toBool()) self.timeoutSpinBox.setValue(settings.value(u'loop delay', QtCore.QVariant(5)).toInt()[0]) - self.currentXValueLabel.setText( - unicode(self.screens.current[u'size'].x())) - self.currentYValueLabel.setText( - unicode(self.screens.current[u'size'].y())) - self.currentHeightValueLabel.setText( - unicode(self.screens.current[u'size'].height())) - self.currentWidthValueLabel.setText( - unicode(self.screens.current[u'size'].width())) self.overrideCheckBox.setChecked(settings.value(u'override position', QtCore.QVariant(False)).toBool()) - self.customXValueEdit.setText(settings.value(u'x position', - QtCore.QVariant(self.screens.current[u'size'].x())).toString()) - self.customYValueEdit.setText(settings.value(u'y position', - QtCore.QVariant(self.screens.current[u'size'].y())).toString()) - self.customHeightValueEdit.setText( - settings.value(u'height', QtCore.QVariant( - self.screens.current[u'size'].height())).toString()) - self.customWidthValueEdit.setText( - settings.value(u'width', QtCore.QVariant( - self.screens.current[u'size'].width())).toString()) + self.customXValueEdit.setValue(settings.value(u'x position', + QtCore.QVariant(self.screens.current[u'size'].x())).toInt()[0]) + self.customYValueEdit.setValue(settings.value(u'y position', + QtCore.QVariant(self.screens.current[u'size'].y())).toInt()[0]) + self.customHeightValueEdit.setValue(settings.value(u'height', + QtCore.QVariant(self.screens.current[u'size'].height())).toInt()[0]) + self.customWidthValueEdit.setValue(settings.value(u'width', + QtCore.QVariant(self.screens.current[u'size'].width())).toInt()[0]) settings.endGroup() self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked()) self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked()) @@ -386,13 +323,13 @@ class GeneralTab(SettingsTab): settings.setValue(u'songselect password', QtCore.QVariant(self.passwordEdit.displayText())) settings.setValue(u'x position', - QtCore.QVariant(self.customXValueEdit.text())) + QtCore.QVariant(self.customXValueEdit.value())) settings.setValue(u'y position', - QtCore.QVariant(self.customYValueEdit.text())) + QtCore.QVariant(self.customYValueEdit.value())) settings.setValue(u'height', - QtCore.QVariant(self.customHeightValueEdit.text())) + QtCore.QVariant(self.customHeightValueEdit.value())) settings.setValue(u'width', - QtCore.QVariant(self.customWidthValueEdit.text())) + QtCore.QVariant(self.customWidthValueEdit.value())) settings.setValue(u'override position', QtCore.QVariant(self.overrideCheckBox.isChecked())) settings.endGroup() @@ -416,10 +353,10 @@ class GeneralTab(SettingsTab): # Reset screens after initial definition if self.overrideChanged: self.screens.override[u'size'] = QtCore.QRect( - int(self.customXValueEdit.validText()), - int(self.customYValueEdit.validText()), - int(self.customWidthValueEdit.validText()), - int(self.customHeightValueEdit.validText())) + self.customXValueEdit.value(), + self.customYValueEdit.value(), + self.customWidthValueEdit.value(), + self.customHeightValueEdit.value()) if self.overrideCheckBox.isChecked(): self.screens.set_override_display() else: diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 06de73309..7e7a6eb8b 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -67,6 +67,7 @@ class MainDisplay(DisplayWidget): self.isLive = live self.alertTab = None self.hideMode = None + self.videoHide = False self.override = {} mainIcon = build_icon(u':/icon/openlp-logo-16x16.png') self.setWindowIcon(mainIcon) @@ -90,8 +91,8 @@ class MainDisplay(DisplayWidget): """ Set up and build the output screen """ - log.debug(u'Setup live = %s for monitor %s ' % (self.isLive, - self.screens.monitor_number)) + log.debug(u'Start setup for monitor %s (live = %s)' % + (self.screens.monitor_number, self.isLive)) self.usePhonon = QtCore.QSettings().value( u'media/use phonon', QtCore.QVariant(True)).toBool() self.phononActive = False @@ -102,13 +103,21 @@ class MainDisplay(DisplayWidget): self.videoWidget.setVisible(False) self.videoWidget.setGeometry(QtCore.QRect(0, 0, self.screen[u'size'].width(), self.screen[u'size'].height())) + log.debug(u'Setup Phonon for monitor %s' % self.screens.monitor_number) self.mediaObject = Phonon.MediaObject(self) self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) Phonon.createPath(self.mediaObject, self.videoWidget) Phonon.createPath(self.mediaObject, self.audio) QtCore.QObject.connect(self.mediaObject, QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'), - self.videoStart) + self.videoState) + QtCore.QObject.connect(self.mediaObject, + QtCore.SIGNAL(u'finished()'), + self.videoFinished) + QtCore.QObject.connect(self.mediaObject, + QtCore.SIGNAL(u'tick(qint64)'), + self.videoTick) + log.debug(u'Setup webView for monitor %s' % self.screens.monitor_number) self.webView = QtWebKit.QWebView(self) self.webView.setGeometry(0, 0, self.screen[u'size'].width(), self.screen[u'size'].height()) @@ -141,29 +150,31 @@ class MainDisplay(DisplayWidget): if not background_color.isValid(): background_color = QtCore.Qt.white splash_image = QtGui.QImage(image_file) - initialFrame = QtGui.QImage( + self.initialFrame = QtGui.QImage( self.screens.current[u'size'].width(), self.screens.current[u'size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) painter_image = QtGui.QPainter() - painter_image.begin(initialFrame) - painter_image.fillRect(initialFrame.rect(), background_color) + painter_image.begin(self.initialFrame) + painter_image.fillRect(self.initialFrame.rect(), background_color) painter_image.drawImage( (self.screens.current[u'size'].width() - splash_image.width()) / 2, (self.screens.current[u'size'].height() - splash_image.height()) / 2, splash_image) serviceItem = ServiceItem() - serviceItem.bg_image_bytes = image_to_byte(initialFrame) + serviceItem.bg_image_bytes = image_to_byte(self.initialFrame) self.webView.setHtml(build_html(serviceItem, self.screen, self.alertTab, self.isLive, None)) - self.initialFrame = True + self.__hideMouse() # To display or not to display? if not self.screen[u'primary']: self.show() self.primary = False else: self.primary = True + log.debug( + u'Finished setup for monitor %s' % self.screens.monitor_number) def text(self, slide): """ @@ -176,6 +187,7 @@ class MainDisplay(DisplayWidget): # Wait for the webview to update before displaying text. while not self.webLoaded: Receiver.send_message(u'openlp_process_events') + self.setGeometry(self.screen[u'size']) self.frame.evaluateJavaScript(u'show_text("%s")' % \ slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) return self.preview() @@ -203,12 +215,18 @@ class MainDisplay(DisplayWidget): else: shrinkItem = self if text: - shrinkItem.resize(self.width(), int(height.toString())) + alert_height = int(height.toString()) + shrinkItem.resize(self.width(), alert_height) shrinkItem.setVisible(True) + if self.alertTab.location == 1: + shrinkItem.move(self.screen[u'size'].left(), + (self.screen[u'size'].height() - alert_height) / 2) + elif self.alertTab.location == 2: + shrinkItem.move(self.screen[u'size'].left(), + self.screen[u'size'].height() - alert_height) else: shrinkItem.setVisible(False) - shrinkItem.resize(self.screen[u'size'].width(), - self.screen[u'size'].height()) + self.setGeometry(self.screen[u'size']) def directImage(self, name, path): """ @@ -232,22 +250,21 @@ class MainDisplay(DisplayWidget): image = self.imageManager.get_image_bytes(name) self.resetVideo() self.displayImage(image) - # show screen - if self.isLive: - self.setVisible(True) return self.preview() def displayImage(self, image): """ Display an image, as is. """ + self.setGeometry(self.screen[u'size']) if image: js = u'show_image("data:image/png;base64,%s");' % image else: js = u'show_image("");' self.frame.evaluateJavaScript(js) # Update the preview frame. - Receiver.send_message(u'maindisplay_active') + if self.isLive: + Receiver.send_message(u'maindisplay_active') def resetImage(self): """ @@ -259,9 +276,11 @@ class MainDisplay(DisplayWidget): self.displayImage(self.serviceItem.bg_image_bytes) else: self.displayImage(None) + # clear the cache self.override = {} # Update the preview frame. - Receiver.send_message(u'maindisplay_active') + if self.isLive: + Receiver.send_message(u'maindisplay_active') def resetVideo(self): """ @@ -278,7 +297,8 @@ class MainDisplay(DisplayWidget): self.frame.evaluateJavaScript(u'show_video("close");') self.override = {} # Update the preview frame. - Receiver.send_message(u'maindisplay_active') + if self.isLive: + Receiver.send_message(u'maindisplay_active') def videoPlay(self): """ @@ -318,7 +338,7 @@ class MainDisplay(DisplayWidget): Changes the volume of a running video """ log.debug(u'videoVolume %d' % volume) - vol = float(volume)/float(10) + vol = float(volume) / float(10) if self.phononActive: self.audio.setVolume(vol) else: @@ -331,10 +351,11 @@ class MainDisplay(DisplayWidget): """ log.debug(u'video') self.webLoaded = True + self.setGeometry(self.screen[u'size']) # We are running a background theme self.override[u'theme'] = u'' self.override[u'video'] = True - vol = float(volume)/float(10) + vol = float(volume) / float(10) if isBackground or not self.usePhonon: js = u'show_video("init", "%s", %s, true); show_video("play");' % \ (videoPath.replace(u'\\', u'\\\\'), str(vol)) @@ -344,21 +365,46 @@ class MainDisplay(DisplayWidget): self.mediaObject.stop() self.mediaObject.clearQueue() self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath)) + # Need the timer to trigger set the trigger to 200ms + # Value taken from web documentation. + if self.serviceItem.start_time != 0: + self.mediaObject.setTickInterval(200) self.mediaObject.play() self.webView.setVisible(False) self.videoWidget.setVisible(True) self.audio.setVolume(vol) # Update the preview frame. - Receiver.send_message(u'maindisplay_active') + if self.isLive: + Receiver.send_message(u'maindisplay_active') return self.preview() - def videoStart(self, newState, oldState): + def videoState(self, newState, oldState): """ Start the video at a predetermined point. """ - if newState == Phonon.PlayingState: + if newState == Phonon.PlayingState \ + and oldState != Phonon.PausedState \ + and self.serviceItem.start_time > 0: + # set start time in milliseconds self.mediaObject.seek(self.serviceItem.start_time * 1000) + def videoFinished(self): + """ + Blank the Video when it has finished so the final frame is not left + hanging + """ + self.videoStop() + self.hideDisplay(HideMode.Blank) + self.phononActive = False + self.videoHide = True + + def videoTick(self, tick): + """ + Triggered on video tick every 200 milli seconds + Will be used to manage stop time later + """ + pass + def isWebLoaded(self): """ Called by webView event to show display is fully loaded @@ -387,9 +433,17 @@ class MainDisplay(DisplayWidget): Receiver.send_message(u'openlp_process_events') # if was hidden keep it hidden if self.isLive: - self.setVisible(True) if self.hideMode: self.hideDisplay(self.hideMode) + else: + # Single screen active + if self.screens.monitor_number == 0: + # Only make visible if setting enabled + if QtCore.QSettings().value(u'general/display on monitor', + QtCore.QVariant(True)).toBool(): + self.setVisible(True) + else: + self.setVisible(True) preview = QtGui.QImage(self.screen[u'size'].width(), self.screen[u'size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) @@ -406,7 +460,7 @@ class MainDisplay(DisplayWidget): """ log.debug(u'buildHtml') self.webLoaded = False - self.initialFrame = False + self.initialFrame = None self.serviceItem = serviceItem background = None # We have an image override so keep the image till the theme changes @@ -415,10 +469,12 @@ class MainDisplay(DisplayWidget): if u'video' in self.override: Receiver.send_message(u'video_background_replaced') self.override = {} + # We have a different theme. elif self.override[u'theme'] != serviceItem.themedata.theme_name: Receiver.send_message(u'live_theme_changed') self.override = {} else: + # replace the background background = self.imageManager. \ get_image_bytes(self.override[u'image']) if self.serviceItem.themedata.background_filename: @@ -434,15 +490,11 @@ class MainDisplay(DisplayWidget): # if was hidden keep it hidden if self.hideMode and self.isLive: self.hideDisplay(self.hideMode) - # Hide mouse cursor when moved over display if enabled in settings - settings = QtCore.QSettings() - if settings.value(u'advanced/hide mouse', - QtCore.QVariant(False)).toBool(): - self.setCursor(QtCore.Qt.BlankCursor) - self.frame.evaluateJavaScript('document.body.style.cursor = "none"') - else: - self.setCursor(QtCore.Qt.ArrowCursor) - self.frame.evaluateJavaScript('document.body.style.cursor = "auto"') + # display hidden for video end we have a new item so must be shown + if self.videoHide and self.isLive: + self.videoHide = False + self.showDisplay() + self.__hideMouse() def footer(self, text): """ @@ -490,7 +542,18 @@ class MainDisplay(DisplayWidget): self.videoPlay() self.hideMode = None # Trigger actions when display is active again - Receiver.send_message(u'maindisplay_active') + if self.isLive: + Receiver.send_message(u'maindisplay_active') + + def __hideMouse(self): + # Hide mouse cursor when moved over display if enabled in settings + if QtCore.QSettings().value(u'advanced/hide mouse', + QtCore.QVariant(False)).toBool(): + self.setCursor(QtCore.Qt.BlankCursor) + self.frame.evaluateJavaScript('document.body.style.cursor = "none"') + else: + self.setCursor(QtCore.Qt.ArrowCursor) + self.frame.evaluateJavaScript('document.body.style.cursor = "auto"') class AudioPlayer(QtCore.QObject): @@ -506,9 +569,6 @@ class AudioPlayer(QtCore.QObject): ``parent`` The parent widget. - - ``screens`` - The list of screens. """ log.debug(u'AudioPlayer Initialisation started') QtCore.QObject.__init__(self, parent) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index b9de8a12e..e421edd98 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -25,6 +25,8 @@ ############################################################################### import logging +import os +from tempfile import gettempdir from PyQt4 import QtCore, QtGui @@ -206,7 +208,7 @@ class Ui_MainWindow(object): mainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode') self.ModeSetupItem = checkable_action(mainWindow, u'ModeLiveItem') mainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode') - self.ModeLiveItem = checkable_action(mainWindow, u'ModeLiveItem') + self.ModeLiveItem = checkable_action(mainWindow, u'ModeLiveItem', True) mainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode') self.ModeGroup = QtGui.QActionGroup(mainWindow) self.ModeGroup.addAction(self.ModeDefaultItem) @@ -225,19 +227,17 @@ class Ui_MainWindow(object): u'Settings') # i18n Language Items self.AutoLanguageItem = checkable_action(mainWindow, - u'AutoLanguageItem') + u'AutoLanguageItem', LanguageManager.auto_language) mainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings') self.LanguageGroup = QtGui.QActionGroup(mainWindow) self.LanguageGroup.setExclusive(True) self.LanguageGroup.setObjectName(u'LanguageGroup') - self.AutoLanguageItem.setChecked(LanguageManager.auto_language) - self.LanguageGroup.setDisabled(LanguageManager.auto_language) + add_actions(self.LanguageGroup, [self.AutoLanguageItem]) qmList = LanguageManager.get_qm_list() savedLanguage = LanguageManager.get_language() for key in sorted(qmList.keys()): - languageItem = checkable_action(mainWindow, key) - if qmList[key] == savedLanguage: - languageItem.setChecked(True) + languageItem = checkable_action( + mainWindow, key, qmList[key] == savedLanguage) add_actions(self.LanguageGroup, [languageItem]) self.SettingsShortcutsItem = icon_action(mainWindow, u'SettingsShortcutsItem', @@ -256,7 +256,6 @@ class Ui_MainWindow(object): u':/system/system_about.png') mainWindow.actionList.add_action(self.HelpAboutItem, u'Help') self.HelpOnlineHelpItem = base_action(mainWindow, u'HelpOnlineHelpItem') - self.HelpOnlineHelpItem.setEnabled(False) mainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help') self.helpWebSiteItem = base_action(mainWindow, u'helpWebSiteItem') mainWindow.actionList.add_action(self.helpWebSiteItem, u'Help') @@ -298,6 +297,12 @@ class Ui_MainWindow(object): QtCore.QObject.connect(self.FileExitItem, QtCore.SIGNAL(u'triggered()'), mainWindow.close) QtCore.QMetaObject.connectSlotsByName(mainWindow) + # Hide the entry, as it does not have any functionality yet. + self.ToolsAddToolItem.setVisible(False) + self.ImportLanguageItem.setVisible(False) + self.ExportLanguageItem.setVisible(False) + self.SettingsShortcutsItem.setVisible(False) + self.HelpDocumentationItem.setVisible(False) def retranslateUi(self, mainWindow): """ @@ -423,16 +428,19 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', 'Ctrl+F1')) self.HelpOnlineHelpItem.setText( translate('OpenLP.MainWindow', '&Online Help')) + # Uncomment after 1.9.5 beta string freeze + #self.HelpOnlineHelpItem.setShortcut( + # translate('OpenLP.MainWindow', 'F1')) self.helpWebSiteItem.setText( translate('OpenLP.MainWindow', '&Web Site')) - self.AutoLanguageItem.setText( - translate('OpenLP.MainWindow', '&Auto Detect')) - self.AutoLanguageItem.setStatusTip(translate('OpenLP.MainWindow', - 'Use the system language, if available.')) for item in self.LanguageGroup.actions(): item.setText(item.objectName()) item.setStatusTip(unicode(translate('OpenLP.MainWindow', 'Set the interface language to %s')) % item.objectName()) + self.AutoLanguageItem.setText( + translate('OpenLP.MainWindow', '&Autodetect')) + self.AutoLanguageItem.setStatusTip(translate('OpenLP.MainWindow', + 'Use the system language, if available.')) self.ToolsAddToolItem.setText( translate('OpenLP.MainWindow', 'Add &Tool...')) self.ToolsAddToolItem.setStatusTip(translate('OpenLP.MainWindow', @@ -468,7 +476,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ QtGui.QMainWindow.__init__(self) self.screens = screens - self.actionList = ActionList() self.applicationVersion = applicationVersion self.clipboard = clipboard # Set up settings sections for the main application @@ -478,6 +485,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.serviceSettingsSection = u'servicemanager' self.songsSettingsSection = u'songs' self.serviceNotSaved = False + self.actionList = ActionList() self.settingsmanager = SettingsManager(screens) self.aboutForm = AboutForm(self, applicationVersion) self.settingsForm = SettingsForm(self.screens, self, self) @@ -523,6 +531,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.ViewThemeManagerItem.setChecked) QtCore.QObject.connect(self.helpWebSiteItem, QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked) + QtCore.QObject.connect(self.HelpOnlineHelpItem, + QtCore.SIGNAL(u'triggered()'), self.onHelpOnLineHelpClicked) QtCore.QObject.connect(self.HelpAboutItem, QtCore.SIGNAL(u'triggered()'), self.onHelpAboutItemClicked) QtCore.QObject.connect(self.ToolsOpenDataFolder, @@ -550,8 +560,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'triggered()'), self.ServiceManagerContents.printServiceOrder) # i18n set signals for languages - QtCore.QObject.connect(self.AutoLanguageItem, - QtCore.SIGNAL(u'toggled(bool)'), self.setAutoLanguage) self.LanguageGroup.triggered.connect(LanguageManager.set_language) QtCore.QObject.connect(self.ModeDefaultItem, QtCore.SIGNAL(u'triggered()'), self.onModeDefaultItemClicked) @@ -650,8 +658,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Show the main form, as well as the display form """ QtGui.QWidget.show(self) - self.liveController.display.setup() - self.previewController.display.setup() if self.liveController.display.isVisible(): self.liveController.display.setFocus() self.activateWindow() @@ -670,6 +676,20 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.setViewMode(False, True, False, False, True) self.ModeLiveItem.setChecked(True) + def firstTime(self): + # Import themes if first time + Receiver.send_message(u'openlp_process_events') + self.themeManagerContents.firstTime() + for plugin in self.pluginManager.plugins: + if hasattr(plugin, u'firstTime'): + Receiver.send_message(u'openlp_process_events') + plugin.firstTime() + Receiver.send_message(u'openlp_process_events') + temp_dir = os.path.join(unicode(gettempdir()), u'openlp') + for filename in os.listdir(temp_dir): + os.remove(os.path.join(temp_dir, filename)) + os.removedirs(temp_dir) + def blankCheck(self): """ Check and display message if screen blank on setup. @@ -703,6 +723,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): import webbrowser webbrowser.open_new(u'http://openlp.org/') + def onHelpOnLineHelpClicked(self): + """ + Load the online OpenLP manual + """ + import webbrowser + webbrowser.open_new(u'http://manual.openlp.org/') + def onHelpAboutItemClicked(self): """ Show the About form diff --git a/openlp/core/ui/mediadockmanager.py b/openlp/core/ui/mediadockmanager.py index 2d388faf4..ef4bc62e0 100644 --- a/openlp/core/ui/mediadockmanager.py +++ b/openlp/core/ui/mediadockmanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/plugindialog.py b/openlp/core/ui/plugindialog.py index 0f6ed9395..0ead739a5 100644 --- a/openlp/core/ui/plugindialog.py +++ b/openlp/core/ui/plugindialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/pluginform.py b/openlp/core/ui/pluginform.py index 15ac62e42..bfac5f3e0 100644 --- a/openlp/core/ui/pluginform.py +++ b/openlp/core/ui/pluginform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/printservicedialog.py b/openlp/core/ui/printservicedialog.py index 41101e8ff..22047eefb 100644 --- a/openlp/core/ui/printservicedialog.py +++ b/openlp/core/ui/printservicedialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index 713e7c27b..cd4b155f8 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py index 4530cfd3c..15dbd9883 100644 --- a/openlp/core/ui/screen.py +++ b/openlp/core/ui/screen.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -25,11 +25,15 @@ ############################################################################### """ The :mod:`screen` module provides management functionality for a machines' -displays +displays. """ import logging import copy +from PyQt4 import QtCore + +from openlp.core.lib import Receiver, translate + log = logging.getLogger(__name__) class ScreenList(object): @@ -38,7 +42,14 @@ class ScreenList(object): """ log.info(u'Screen loaded') - def __init__(self): + def __init__(self, desktop): + """ + Initialise the screen list. + + ``desktop`` + A ``QDesktopWidget`` object. + """ + self.desktop = desktop self.preview = None self.current = None self.override = None @@ -48,19 +59,120 @@ class ScreenList(object): self.current_display = 0 # save config display number self.monitor_number = 0 + self.screen_count_changed() + QtCore.QObject.connect(desktop, + QtCore.SIGNAL(u'resized(int)'), self.screen_resolution_changed) + QtCore.QObject.connect(desktop, + QtCore.SIGNAL(u'screenCountChanged(int)'), + self.screen_count_changed) + + def screen_resolution_changed(self, number): + """ + Called when the resolution of a screen has changed. + + ``number`` + The number of the screen, which size has changed. + """ + log.info(u'screenResolutionChanged %d' % number) + for screen in self.screen_list: + if number == screen[u'number']: + newScreen = { + u'number': number, + u'size': self.desktop.screenGeometry(number), + u'primary': self.desktop.primaryScreen() == number + } + self.remove_screen(number) + self.add_screen(newScreen) + # The screen's default size is used, that is why we have to + # update the override screen. + if screen == self.override: + self.override = copy.deepcopy(newScreen) + self.set_override_display() + Receiver.send_message(u'config_screen_changed') + break + + def screen_count_changed(self, changed_screen=-1): + """ + Called when a screen has been added or removed. + + ``changed_screen`` + The screen's number which has been (un)plugged. + """ + # Remove unplugged screens. + for screen in copy.deepcopy(self.screen_list): + if screen[u'number'] == self.desktop.numScreens(): + self.remove_screen(screen[u'number']) + # Add new screens. + for number in xrange(0, self.desktop.numScreens()): + if not self.screen_exists(number): + self.add_screen({ + u'number': number, + u'size': self.desktop.screenGeometry(number), + u'primary': (self.desktop.primaryScreen() == number) + }) + # We do not want to send this message, when the method is called the + # first time. + if changed_screen != -1: + # Reload setting tabs to apply possible changes. + Receiver.send_message(u'config_screen_changed') + + def get_screen_list(self): + """ + Returns a list with the screens. This should only be used to display + available screens to the user:: + + [u'Screen 1 (primary)', u'Screen 2'] + """ + screen_list = [] + for screen in self.screen_list: + screen_name = u'%s %d' % (translate('OpenLP.ScreenList', 'Screen'), + screen[u'number'] + 1) + if screen[u'primary']: + screen_name = u'%s (%s)' % (screen_name, + translate('OpenLP.ScreenList', 'primary')) + screen_list.append(screen_name) + return screen_list def add_screen(self, screen): """ - Add a screen to the list of known screens + Add a screen to the list of known screens. + + ``screen`` + A dict with the screen properties:: + + { + u'primary': True, + u'number': 0, + u'size': PyQt4.QtCore.QRect(0, 0, 1024, 768) + } """ + log.info(u'Screen %d found with resolution %s', + screen[u'number'], screen[u'size']) if screen[u'primary']: self.current = screen self.screen_list.append(screen) self.display_count += 1 + def remove_screen(self, number): + """ + Remove a screen from the list of known screens. + + ``number`` + The screen number (int). + """ + log.info(u'remove_screen %d' % number) + for screen in self.screen_list: + if screen[u'number'] == number: + self.screen_list.remove(screen) + self.display_count -= 1 + break + def screen_exists(self, number): """ - Confirms a screen is known + Confirms a screen is known. + + ``number`` + The screen number (int). """ for screen in self.screen_list: if screen[u'number'] == number: @@ -69,7 +181,10 @@ class ScreenList(object): def set_current_display(self, number): """ - Set up the current screen dimensions + Set up the current screen dimensions. + + ``number`` + The screen number (int). """ log.debug(u'set_current_display %s', number) if number + 1 > self.display_count: @@ -86,8 +201,8 @@ class ScreenList(object): def set_override_display(self): """ - replace the current size with the override values - user wants to have their own screen attributes + Replace the current size with the override values, as the user wants to + have their own screen attributes. """ log.debug(u'set_override_display') self.current = copy.deepcopy(self.override) @@ -95,8 +210,8 @@ class ScreenList(object): def reset_current_display(self): """ - replace the current values with the correct values - user wants to use the correct screen attributes + Replace the current values with the correct values, as the user wants to + use the correct screen attributes. """ log.debug(u'reset_current_display') self.set_current_display(self.current_display) diff --git a/openlp/core/ui/serviceitemeditdialog.py b/openlp/core/ui/serviceitemeditdialog.py index f2909eabb..4e966a38b 100644 --- a/openlp/core/ui/serviceitemeditdialog.py +++ b/openlp/core/ui/serviceitemeditdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/serviceitemeditform.py b/openlp/core/ui/serviceitemeditform.py index 588bdbfd6..165087b69 100644 --- a/openlp/core/ui/serviceitemeditform.py +++ b/openlp/core/ui/serviceitemeditform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index f5a08d8b2..d9d9c7287 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -49,6 +49,19 @@ class ServiceManagerList(QtGui.QTreeWidget): QtGui.QTreeWidget.__init__(self, parent) self.mainwindow = mainwindow + def keyPressEvent(self, event): + if isinstance(event, QtGui.QKeyEvent): + # here accept the event and do something + if event.key() == QtCore.Qt.Key_Up: + self.mainwindow.onMoveSelectionUp() + event.accept() + elif event.key() == QtCore.Qt.Key_Down: + self.mainwindow.onMoveSelectionDown() + event.accept() + event.ignore() + else: + event.ignore() + def mouseMoveEvent(self, event): """ Drag and drop event does not care what data is selected @@ -197,13 +210,13 @@ class ServiceManager(QtGui.QWidget): u':/services/service_expand_all.png', translate('OpenLP.ServiceManager', 'Expand all the service items.'), - self.onExpandAll) + self.onExpandAll, shortcut=QtCore.Qt.Key_Plus) self.serviceManagerList.collapse = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', '&Collapse all'), u':/services/service_collapse_all.png', translate('OpenLP.ServiceManager', 'Collapse all the service items.'), - self.onCollapseAll) + self.onCollapseAll, shortcut=QtCore.Qt.Key_Minus) self.orderToolbar.addSeparator() self.serviceManagerList.makeLive = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', 'Go Live'), @@ -293,7 +306,9 @@ class ServiceManager(QtGui.QWidget): self.serviceManagerList.moveTop, self.serviceManagerList.moveBottom, self.serviceManagerList.up, - self.serviceManagerList.down + self.serviceManagerList.down, + self.serviceManagerList.expand, + self.serviceManagerList.collapse ]) self.configUpdated() @@ -306,6 +321,9 @@ class ServiceManager(QtGui.QWidget): actionList.add_action(self.serviceManagerList.makeLive, u'Service') actionList.add_action(self.serviceManagerList.up, u'Service') actionList.add_action(self.serviceManagerList.down, u'Service') + actionList.add_action(self.serviceManagerList.expand, u'Service') + actionList.add_action(self.serviceManagerList.collapse, u'Service') + def setModified(self, modified=True): """ @@ -415,47 +433,75 @@ class ServiceManager(QtGui.QWidget): """ if not self.fileName(): return self.saveFileAs() - else: - fileName = self.fileName() - log.debug(u'ServiceManager.saveFile - %s' % fileName) - SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, - split_filename(fileName)[0]) - service = [] - serviceFileName = fileName.replace(u'.osz', u'.osd') - zip = None - file = None - try: - write_list = [] - zip = zipfile.ZipFile(unicode(fileName), 'w') - for item in self.serviceItems: - service.append({u'serviceitem': \ - item[u'service_item'].get_service_repr()}) - if item[u'service_item'].uses_file(): - for frame in item[u'service_item'].get_frames(): - if item[u'service_item'].is_image(): - path_from = frame[u'path'] - else: - path_from = unicode(os.path.join( - frame[u'path'], - frame[u'title'])) - # On write a file once - if not path_from in write_list: - write_list.append(path_from) - zip.write(path_from.encode(u'utf-8')) - file = open(serviceFileName, u'wb') - cPickle.dump(service, file) - file.close() - zip.write(serviceFileName.encode(u'utf-8')) - except IOError: - log.exception(u'Failed to save service to disk') - finally: - if file: - file.close() - if zip: - zip.close() - delete_file(serviceFileName) - self.mainwindow.addRecentFile(fileName) - self.setModified(False) + path_file_name = unicode(self.fileName()) + (path, file_name) = os.path.split(path_file_name) + (basename, extension) = os.path.splitext(file_name) + service_file_name = basename + '.osd' + log.debug(u'ServiceManager.saveFile - %s' % path_file_name) + SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, + path) + service = [] + write_list = [] + total_size = 0 + for item in self.serviceItems: + service.append({u'serviceitem': + item[u'service_item'].get_service_repr()}) + if not item[u'service_item'].uses_file(): + continue + for frame in item[u'service_item'].get_frames(): + if item[u'service_item'].is_image(): + path_from = frame[u'path'] + else: + path_from = os.path.join(frame[u'path'], frame[u'title']) + # Only write a file once + if path_from in write_list: + continue + file_size = os.path.getsize(path_from) + size_limit = 52428800 # 50MiB + #if file_size > size_limit: + # # File exeeds size_limit bytes, ask user + # message = unicode(translate('OpenLP.ServiceManager', + # 'Do you want to include \n%.1f MB file "%s"\n' + # 'into the service file?\nThis may take some time.\n\n' + # 'Please note that you need to\ntake care of that file' + # ' yourself,\nif you leave it out.')) % \ + # (file_size/1048576, os.path.split(path_from)[1]) + # ans = QtGui.QMessageBox.question(self.mainwindow, + # translate('OpenLP.ServiceManager', 'Including Large ' + # 'File'), message, QtGui.QMessageBox.StandardButtons( + # QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel), + # QtGui.QMessageBox.Ok) + # if ans == QtGui.QMessageBox.Cancel: + # continue + write_list.append(path_from) + total_size += file_size + log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' % + total_size) + service_content = cPickle.dumps(service) + # Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be + # extracted using unzip in UNIX. + allow_zip_64 = (total_size > 2147483648 + len(service_content)) + log.debug(u'ServiceManager.saveFile - allowZip64 is %s' % + allow_zip_64) + zip = None + try: + zip = zipfile.ZipFile(path_file_name, 'w', zipfile.ZIP_STORED, + allow_zip_64) + # First we add service contents. + # We save ALL filenames into ZIP using UTF-8. + zip.writestr(service_file_name.encode(u'utf-8'), + service_content) + # Finally add all the listed media files. + for path_from in write_list: + zip.write(path_from, path_from.encode(u'utf-8')) + except IOError: + log.exception(u'Failed to save service to disk') + return False + finally: + if zip: + zip.close() + self.mainwindow.addRecentFile(path_file_name) + self.setModified(False) return True def saveFileAs(self): @@ -572,7 +618,7 @@ class ServiceManager(QtGui.QWidget): if item.parent() is None: self.notesAction.setVisible(True) if serviceItem[u'service_item']\ - .is_capable(ItemCapabilities.AllowsVarableStartTime): + .is_capable(ItemCapabilities.AllowsVariableStartTime): self.timeAction.setVisible(True) self.themeMenu.menuAction().setVisible(False) if serviceItem[u'service_item'].is_text(): @@ -859,7 +905,7 @@ class ServiceManager(QtGui.QWidget): child.setText(0, text[:40]) child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count)) if item[u'service_item'] \ - .is_capable(ItemCapabilities.AllowsVarableStartTime): + .is_capable(ItemCapabilities.AllowsVariableStartTime): tip = item[u'service_item'].get_media_time() if tip: child.setToolTip(0, tip) @@ -943,6 +989,7 @@ class ServiceManager(QtGui.QWidget): for item in self.serviceItems: if item[u'service_item']._uuid == uuid: item[u'service_item'].edit_id = editId + self.setModified(True) def replaceServiceItem(self, newItem): """ @@ -1123,13 +1170,14 @@ class ServiceManager(QtGui.QWidget): self.serviceItems.remove(serviceItem) self.serviceItems.insert(endpos, serviceItem) self.repaintServiceList(endpos, child) + self.setModified(True) else: # we are not over anything so drop replace = False if item is None: self.dropPosition = len(self.serviceItems) else: - # we are over somthing so lets investigate + # we are over something so lets investigate pos = self._getParentItemData(item) - 1 serviceItem = self.serviceItems[pos] if (plugin == serviceItem[u'service_item'].name and diff --git a/openlp/core/ui/servicenoteform.py b/openlp/core/ui/servicenoteform.py index 200e12818..ef1c627d4 100644 --- a/openlp/core/ui/servicenoteform.py +++ b/openlp/core/ui/servicenoteform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/settingsdialog.py b/openlp/core/ui/settingsdialog.py index af8ba84ab..70f83f4fa 100644 --- a/openlp/core/ui/settingsdialog.py +++ b/openlp/core/ui/settingsdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 872b37586..cf66ad090 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/shortcutlistdialog.py b/openlp/core/ui/shortcutlistdialog.py index b4673f410..4e5b9e270 100644 --- a/openlp/core/ui/shortcutlistdialog.py +++ b/openlp/core/ui/shortcutlistdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/shortcutlistform.py b/openlp/core/ui/shortcutlistform.py index 4f770045c..e87ba3ada 100644 --- a/openlp/core/ui/shortcutlistform.py +++ b/openlp/core/ui/shortcutlistform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 8d612676b..6af25d344 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -32,7 +32,7 @@ from PyQt4.phonon import Phonon from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \ ItemCapabilities, translate -from openlp.core.lib.ui import UiStrings, shortcut_action +from openlp.core.lib.ui import icon_action, UiStrings, shortcut_action from openlp.core.ui import HideMode, MainDisplay log = logging.getLogger(__name__) @@ -46,7 +46,6 @@ class SlideList(QtGui.QTableWidget): QtGui.QTableWidget.__init__(self, parent.controller) self.parent = parent - class SlideController(QtGui.QWidget): """ SlideController is the slide controller widget. This widget is what the @@ -114,11 +113,11 @@ class SlideController(QtGui.QWidget): self.previewListWidget = SlideList(self) self.previewListWidget.setColumnCount(1) self.previewListWidget.horizontalHeader().setVisible(False) - self.previewListWidget.setColumnWidth( - 0, self.controller.width()) + self.previewListWidget.setColumnWidth(0, self.controller.width()) self.previewListWidget.isLive = self.isLive self.previewListWidget.setObjectName(u'PreviewListWidget') - self.previewListWidget.setSelectionBehavior(1) + self.previewListWidget.setSelectionBehavior( + QtGui.QAbstractItemView.SelectRows) self.previewListWidget.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self.previewListWidget.setEditTriggers( @@ -146,36 +145,30 @@ class SlideController(QtGui.QWidget): u':/slides/slide_next.png', translate('OpenLP.SlideController', 'Move to next'), self.onSlideSelectedNext) + self.toolbar.addToolbarSeparator(u'Close Separator') if self.isLive: - self.toolbar.addToolbarSeparator(u'Close Separator') self.hideMenu = QtGui.QToolButton(self.toolbar) self.hideMenu.setText(translate('OpenLP.SlideController', 'Hide')) self.hideMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup) self.toolbar.addToolbarWidget(u'Hide Menu', self.hideMenu) self.hideMenu.setMenu(QtGui.QMenu( translate('OpenLP.SlideController', 'Hide'), self.toolbar)) - self.blankScreen = QtGui.QAction(QtGui.QIcon( - u':/slides/slide_blank.png'), - translate('OpenLP.SlideController', - 'Blank Screen'), self.hideMenu) - self.blankScreen.setCheckable(True) - self.themeScreen = QtGui.QAction(QtGui.QIcon( - u':/slides/slide_theme.png'), - translate('OpenLP.SlideController', - 'Blank to Theme'), self.hideMenu) - self.themeScreen.setCheckable(True) + self.blankScreen = icon_action(self.hideMenu, u'Blank Screen', + u':/slides/slide_blank.png', False) + self.blankScreen.setText( + translate('OpenLP.SlideController', 'Blank Screen')) + self.themeScreen = icon_action(self.hideMenu, u'Blank Theme', + u':/slides/slide_theme.png', False) + self.themeScreen.setText( + translate('OpenLP.SlideController', 'Blank to Theme')) + self.desktopScreen = icon_action(self.hideMenu, u'Desktop Screen', + u':/slides/slide_desktop.png', False) + self.desktopScreen.setText( + translate('OpenLP.SlideController', 'Show Desktop')) self.hideMenu.setDefaultAction(self.blankScreen) self.hideMenu.menu().addAction(self.blankScreen) self.hideMenu.menu().addAction(self.themeScreen) - if self.screens.display_count > 1: - self.desktopScreen = QtGui.QAction(QtGui.QIcon( - u':/slides/slide_desktop.png'), - translate('OpenLP.SlideController', - 'Show Desktop'), self.hideMenu) - self.hideMenu.menu().addAction(self.desktopScreen) - self.desktopScreen.setCheckable(True) - QtCore.QObject.connect(self.desktopScreen, - QtCore.SIGNAL(u'triggered(bool)'), self.onHideDisplay) + self.hideMenu.menu().addAction(self.desktopScreen) self.toolbar.addToolbarSeparator(u'Loop Separator') self.toolbar.addToolbarButton( # Does not need translating - control string. @@ -195,7 +188,6 @@ class SlideController(QtGui.QWidget): self.delaySpinBox.setToolTip(translate('OpenLP.SlideController', 'Delay between slides in seconds')) else: - self.toolbar.addToolbarSeparator(u'Close Separator') self.toolbar.addToolbarButton( # Does not need translating - control string. u'Go Live', u':/general/general_live.png', @@ -226,8 +218,7 @@ class SlideController(QtGui.QWidget): if self.isLive: # Build the Song Toolbar self.songMenu = QtGui.QToolButton(self.toolbar) - self.songMenu.setText(translate('OpenLP.SlideController', - 'Go To')) + self.songMenu.setText(translate('OpenLP.SlideController', 'Go To')) self.songMenu.setPopupMode(QtGui.QToolButton.InstantPopup) self.toolbar.addToolbarWidget(u'Song Menu', self.songMenu) self.songMenu.setMenu(QtGui.QMenu( @@ -303,6 +294,8 @@ class SlideController(QtGui.QWidget): QtCore.SIGNAL(u'triggered(bool)'), self.onBlankDisplay) QtCore.QObject.connect(self.themeScreen, QtCore.SIGNAL(u'triggered(bool)'), self.onThemeDisplay) + QtCore.QObject.connect(self.desktopScreen, + QtCore.SIGNAL(u'triggered(bool)'), self.onHideDisplay) QtCore.QObject.connect(self.volumeSlider, QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume) QtCore.QObject.connect(Receiver.get_receiver(), @@ -469,6 +462,9 @@ class SlideController(QtGui.QWidget): self.onSlideSelected() def receiveSpinDelay(self, value): + """ + Adjusts the value of the ``delaySpinBox`` to the given one. + """ self.delaySpinBox.setValue(int(value)) def enableToolBar(self, item): @@ -624,6 +620,11 @@ class SlideController(QtGui.QWidget): self.parent.renderManager.width, self.parent.renderManager.height) else: + # If current slide set background to image + if framenumber == slideno: + self.serviceItem.bg_image_bytes = \ + self.parent.renderManager.image_manager. \ + get_image_bytes(frame[u'title']) image = self.parent.renderManager.image_manager. \ get_image(frame[u'title']) label.setPixmap(QtGui.QPixmap.fromImage(image)) @@ -747,8 +748,7 @@ class SlideController(QtGui.QWidget): self.hideMenu.setDefaultAction(self.blankScreen) self.blankScreen.setChecked(checked) self.themeScreen.setChecked(False) - if self.screens.display_count > 1: - self.desktopScreen.setChecked(False) + self.desktopScreen.setChecked(False) if checked: Receiver.send_message(u'maindisplay_hide', HideMode.Blank) QtCore.QSettings().setValue( @@ -769,8 +769,7 @@ class SlideController(QtGui.QWidget): self.hideMenu.setDefaultAction(self.themeScreen) self.blankScreen.setChecked(False) self.themeScreen.setChecked(checked) - if self.screens.display_count > 1: - self.desktopScreen.setChecked(False) + self.desktopScreen.setChecked(False) if checked: Receiver.send_message(u'maindisplay_hide', HideMode.Theme) QtCore.QSettings().setValue( @@ -791,9 +790,6 @@ class SlideController(QtGui.QWidget): self.hideMenu.setDefaultAction(self.desktopScreen) self.blankScreen.setChecked(False) self.themeScreen.setChecked(False) - # On valid if more than 1 display - if self.screens.display_count <= 1: - return self.desktopScreen.setChecked(checked) if checked: Receiver.send_message(u'maindisplay_hide', HideMode.Screen) @@ -857,8 +853,11 @@ class SlideController(QtGui.QWidget): frame = self.display.text(toDisplay) else: frame = self.display.image(toDisplay) + # reset the store used to display first image + self.serviceItem.bg_image_bytes = None self.slidePreview.setPixmap(QtGui.QPixmap.fromImage(frame)) self.selectedRow = row + self.__checkUpdateSelectedSlide(row) Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, row) @@ -1096,15 +1095,15 @@ class SlideController(QtGui.QWidget): Used by command items which provide their own displays to reset the screen hide attributes """ + blank = None if self.blankScreen.isChecked: - self.blankScreen.setChecked(False) - self.hideMenu.setDefaultAction(self.blankScreen) + blank = self.blankScreen + if self.themeScreen.isChecked: + blank = self.themeScreen + if self.desktopScreen.isChecked: + blank = self.desktopScreen + if blank: + blank.setChecked(False) + self.hideMenu.setDefaultAction(blank) QtCore.QSettings().remove( self.parent.generalSettingsSection + u'/screen blank') - if self.themeScreen.isChecked: - self.themeScreen.setChecked(False) - self.hideMenu.setDefaultAction(self.themeScreen) - if self.screens.display_count > 1: - if self.desktopScreen.isChecked: - self.desktopScreen.setChecked(False) - self.hideMenu.setDefaultAction(self.desktopScreen) diff --git a/openlp/core/ui/splashscreen.py b/openlp/core/ui/splashscreen.py index 88c6f09f9..84aa1d7df 100644 --- a/openlp/core/ui/splashscreen.py +++ b/openlp/core/ui/splashscreen.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/starttimedialog.py b/openlp/core/ui/starttimedialog.py index 14ef84aac..2da3a4ade 100644 --- a/openlp/core/ui/starttimedialog.py +++ b/openlp/core/ui/starttimedialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/starttimeform.py b/openlp/core/ui/starttimeform.py index 01800602f..1a13e3733 100644 --- a/openlp/core/ui/starttimeform.py +++ b/openlp/core/ui/starttimeform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index cc490bf9b..6653e7e1d 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 0e04d7b46..11d10413c 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -145,6 +145,20 @@ class ThemeManager(QtGui.QWidget): # Last little bits of setting up self.configUpdated() + def firstTime(self): + """ + Import new themes downloaded by the first time wizard + """ + Receiver.send_message(u'cursor_busy') + encoding = get_filesystem_encoding() + files = SettingsManager.get_files(self.settingsSection, u'.otz') + for file in files: + file = os.path.join(self.path, file).encode(encoding) + self.unzipTheme(file, self.path) + delete_file(file) + self.loadThemes() + Receiver.send_message(u'cursor_normal') + def configUpdated(self, firstTime=False): """ Triggered when Config dialog is updated. @@ -370,6 +384,7 @@ class ThemeManager(QtGui.QWidget): 'Save Theme - (%s)')) % theme, SettingsManager.get_last_dir(self.settingsSection, 1)) path = unicode(path) + Receiver.send_message(u'cursor_busy') if path: SettingsManager.set_last_dir(self.settingsSection, path, 1) themePath = os.path.join(path, theme + u'.otz') @@ -395,6 +410,7 @@ class ThemeManager(QtGui.QWidget): finally: if zip: zip.close() + Receiver.send_message(u'cursor_normal') def onImportTheme(self): """ @@ -408,12 +424,14 @@ class ThemeManager(QtGui.QWidget): unicode(translate('OpenLP.ThemeManager', 'OpenLP Themes (*.theme *.otz)'))) log.info(u'New Themes %s', unicode(files)) - if files: - for file in files: - SettingsManager.set_last_dir( - self.settingsSection, unicode(file)) - self.unzipTheme(file, self.path) + if not files: + return + Receiver.send_message(u'cursor_busy') + for file in files: + SettingsManager.set_last_dir(self.settingsSection, unicode(file)) + self.unzipTheme(file, self.path) self.loadThemes() + Receiver.send_message(u'cursor_normal') def loadThemes(self): """ @@ -484,16 +502,16 @@ class ThemeManager(QtGui.QWidget): def unzipTheme(self, filename, dir): """ Unzip the theme, remove the preview file if stored - Generate a new preview fileCheck the XML theme version and upgrade if + Generate a new preview file. Check the XML theme version and upgrade if necessary. """ log.debug(u'Unzipping theme %s', filename) filename = unicode(filename) zip = None outfile = None + filexml = None try: zip = zipfile.ZipFile(filename) - filexml = None themename = None for file in zip.namelist(): ucsfile = file_is_unicode(file) @@ -529,7 +547,7 @@ class ThemeManager(QtGui.QWidget): else: outfile = open(fullpath, u'wb') outfile.write(zip.read(file)) - except (IOError, NameError): + except (IOError, NameError, zipfile.BadZipfile): critical_error_message_box( translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', 'File is not a valid theme.')) @@ -544,7 +562,9 @@ class ThemeManager(QtGui.QWidget): if filexml: theme = self._createThemeFromXml(filexml, self.path) self.generateAndSaveImage(dir, themename, theme) - else: + # Only show the error message, when IOError was not raised (in this + # case the error message has already been shown). + elif zip is not None: critical_error_message_box( translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index c7442744f..1b76d2198 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index 20cca69c6..9e464aa7a 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/ui/wizard.py b/openlp/core/ui/wizard.py index 0b275733e..cb3a75294 100644 --- a/openlp/core/ui/wizard.py +++ b/openlp/core/ui/wizard.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 70b994653..751e2b3a8 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -35,6 +35,7 @@ import urllib2 from datetime import datetime from PyQt4 import QtGui, QtCore + if sys.platform != u'win32' and sys.platform != u'darwin': try: from xdg import BaseDirectory @@ -134,7 +135,7 @@ class AppLocation(object): elif dir_type == AppLocation.LanguageDir: app_path = _get_frozen_path( os.path.abspath(os.path.split(sys.argv[0])[0]), - os.path.split(openlp.__file__)[0]) + _get_os_dir_path(dir_type)) return os.path.join(app_path, u'i18n') else: return _get_os_dir_path(dir_type) @@ -169,15 +170,21 @@ def _get_os_dir_path(dir_type): if dir_type == AppLocation.DataDir: return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data') + elif dir_type == AppLocation.LanguageDir: + return os.path.split(openlp.__file__)[0] return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp') elif sys.platform == u'darwin': if dir_type == AppLocation.DataDir: return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp', u'Data') + elif dir_type == AppLocation.LanguageDir: + return os.path.split(openlp.__file__)[0] return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp') else: + if dir_type == AppLocation.LanguageDir: + return os.path.join(u'/usr', u'share', u'openlp') if XDG_BASE_AVAILABLE: if dir_type == AppLocation.ConfigDir: return os.path.join(unicode(BaseDirectory.xdg_config_home, @@ -337,6 +344,7 @@ def get_web_page(url, header=None, update_openlp=False): return None if update_openlp: Receiver.send_message(u'openlp_process_events') + log.debug(page) return page def file_is_unicode(filename): @@ -383,7 +391,7 @@ def get_uno_command(): Returns the UNO command to launch an openoffice.org instance. """ COMMAND = u'soffice' - OPTIONS = u'-nologo -norestore -minimized -invisible -nofirststartwizard' + OPTIONS = u'-nologo -norestore -minimized -nodefault -nofirststartwizard' if UNO_CONNECTION_TYPE == u'pipe': CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"' else: diff --git a/openlp/core/utils/actions.py b/openlp/core/utils/actions.py index 30d1d7586..41ae41f4b 100644 --- a/openlp/core/utils/actions.py +++ b/openlp/core/utils/actions.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py index ced2fa843..caea3bfdd 100644 --- a/openlp/core/utils/languagemanager.py +++ b/openlp/core/utils/languagemanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -63,6 +63,8 @@ class LanguageManager(object): """ Find all available language files in this OpenLP install """ + log.debug(u'Translation files: %s', AppLocation.get_directory( + AppLocation.LanguageDir)) trans_dir = QtCore.QDir(AppLocation.get_directory( AppLocation.LanguageDir)) file_names = trans_dir.entryList(QtCore.QStringList(u'*.qm'), @@ -100,27 +102,35 @@ class LanguageManager(object): return language @staticmethod - def set_language(action): + def set_language(action, message=True): """ Set the language to translate OpenLP into ``action`` The language menu option + + ``message`` + Display the message option """ language = u'en' if action: - action_name = u'%s' % action.objectName() - qm_list = LanguageManager.get_qm_list() - language = u'%s' % qm_list[action_name] + action_name = unicode(action.objectName()) + if action_name == u'AutoLanguageItem': + LanguageManager.auto_language = True + else: + LanguageManager.auto_language = False + qm_list = LanguageManager.get_qm_list() + language = unicode(qm_list[action_name]) if LanguageManager.auto_language: language = u'[%s]' % language QtCore.QSettings().setValue( u'general/language', QtCore.QVariant(language)) log.info(u'Language file: \'%s\' written to conf file' % language) - QtGui.QMessageBox.information(None, - translate('OpenLP.LanguageManager', 'Language'), - translate('OpenLP.LanguageManager', - 'Please restart OpenLP to use your new language setting.')) + if message: + QtGui.QMessageBox.information(None, + translate('OpenLP.LanguageManager', 'Language'), + translate('OpenLP.LanguageManager', + 'Please restart OpenLP to use your new language setting.')) @staticmethod def init_qm_list(): diff --git a/openlp/plugins/__init__.py b/openlp/plugins/__init__.py index 5fd39d572..7a160a316 100644 --- a/openlp/plugins/__init__.py +++ b/openlp/plugins/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/__init__.py b/openlp/plugins/alerts/__init__.py index f3c629b25..3a0892d49 100644 --- a/openlp/plugins/alerts/__init__.py +++ b/openlp/plugins/alerts/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 1d9bd4c61..db0ba3b7e 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -40,7 +40,7 @@ class AlertsPlugin(Plugin): log.info(u'Alerts Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Alerts', u'1.9.4', plugin_helpers, + Plugin.__init__(self, u'Alerts', plugin_helpers, settingsTabClass=AlertsTab) self.weight = -3 self.icon = build_icon(u':/plugins/plugin_alerts.png') diff --git a/openlp/plugins/alerts/forms/__init__.py b/openlp/plugins/alerts/forms/__init__.py index e2809ed73..bb4a9940f 100644 --- a/openlp/plugins/alerts/forms/__init__.py +++ b/openlp/plugins/alerts/forms/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/forms/alertdialog.py b/openlp/plugins/alerts/forms/alertdialog.py index 27b0b0f7d..da788f2bd 100644 --- a/openlp/plugins/alerts/forms/alertdialog.py +++ b/openlp/plugins/alerts/forms/alertdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/forms/alertform.py b/openlp/plugins/alerts/forms/alertform.py index 75475d524..b87ff3c5d 100644 --- a/openlp/plugins/alerts/forms/alertform.py +++ b/openlp/plugins/alerts/forms/alertform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -163,7 +163,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog): # We found '<>' in the alert text, but the ParameterEdit field is empty. if text.find(u'<>') != -1 and not self.parameterEdit.text() and \ QtGui.QMessageBox.question(self, - translate('AlertPlugin.AlertForm', 'No Parameter found'), + translate('AlertPlugin.AlertForm', 'No Parameter Found'), translate('AlertPlugin.AlertForm', 'You have not entered a ' 'parameter to be replaced.\nDo you want to continue anyway?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | @@ -174,9 +174,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog): # in the alert text. elif text.find(u'<>') == -1 and self.parameterEdit.text() and \ QtGui.QMessageBox.question(self, - translate('AlertPlugin.AlertForm', 'No Placeholder found'), + translate('AlertPlugin.AlertForm', 'No Placeholder Found'), translate('AlertPlugin.AlertForm', 'The alert text does not' - ' contain \'<>\'.\nDo want to continue anyway?'), + ' contain \'<>\'.\nDo you want to continue anyway?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: self.parameterEdit.setFocus() diff --git a/openlp/plugins/alerts/lib/__init__.py b/openlp/plugins/alerts/lib/__init__.py index 3b446b67d..39cbbfe59 100644 --- a/openlp/plugins/alerts/lib/__init__.py +++ b/openlp/plugins/alerts/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py index a05a29575..d12fb41ec 100644 --- a/openlp/plugins/alerts/lib/alertsmanager.py +++ b/openlp/plugins/alerts/lib/alertsmanager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 5b4f670a3..698cbfa2a 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/alerts/lib/db.py b/openlp/plugins/alerts/lib/db.py index 9cfa34846..72c671620 100644 --- a/openlp/plugins/alerts/lib/db.py +++ b/openlp/plugins/alerts/lib/db.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/bibles/__init__.py b/openlp/plugins/bibles/__init__.py index 29364ab1a..5a2035e13 100644 --- a/openlp/plugins/bibles/__init__.py +++ b/openlp/plugins/bibles/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 73a9b7e1d..4f677f211 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -37,7 +37,7 @@ class BiblePlugin(Plugin): log.info(u'Bible Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Bibles', u'1.9.4', plugin_helpers, + Plugin.__init__(self, u'Bibles', plugin_helpers, BibleMediaItem, BiblesTab) self.weight = -9 self.icon_path = u':/plugins/plugin_bibles.png' @@ -50,7 +50,8 @@ class BiblePlugin(Plugin): self.manager = BibleManager(self) Plugin.initialise(self) self.importBibleItem.setVisible(True) - self.exportBibleItem.setVisible(True) + # Set to invisible until we can export bibles + self.exportBibleItem.setVisible(False) def finalise(self): """ diff --git a/openlp/plugins/bibles/forms/__init__.py b/openlp/plugins/bibles/forms/__init__.py index 15f14de9e..e6897e53f 100644 --- a/openlp/plugins/bibles/forms/__init__.py +++ b/openlp/plugins/bibles/forms/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 67996e158..117ffaf4c 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -568,7 +568,8 @@ class BibleImportForm(OpenLPWizard): """ self.getFileName(WizardStrings.OpenTypeFile % UiStrings.OLPV1, self.openlp1FileEdit, u'%s (*.bible)' % - translate('BiblesPlugin.ImportWizardForm', 'openlp.org 1.x bible')) + translate('BiblesPlugin.ImportWizardForm', + 'openlp.org 1.x Bible Files')) def registerFields(self): """ diff --git a/openlp/plugins/bibles/lib/__init__.py b/openlp/plugins/bibles/lib/__init__.py index e8634c3a3..e219fbc00 100644 --- a/openlp/plugins/bibles/lib/__init__.py +++ b/openlp/plugins/bibles/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -268,6 +268,7 @@ class SearchResults(object): return len(self.verselist) > 0 +from versereferencelist import VerseReferenceList from manager import BibleManager from biblestab import BiblesTab from mediaitem import BibleMediaItem diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index 74be7145b..7a631ad09 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index 18bf06cfb..9ff7394d1 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -69,8 +69,6 @@ import logging import chardet import csv -from PyQt4 import QtCore - from openlp.core.lib import Receiver, translate from openlp.plugins.bibles.lib.db import BibleDB, Testament diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 5cf000ee1..85ab98de1 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index e2dde59fd..6a6ef131a 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -227,6 +227,10 @@ class BGExtract(object): cleanup = [(re.compile('\s+'), lambda match: ' ')] verses = BeautifulSoup(str(soup), markupMassage=cleanup) verse_list = {} + # Cater for inconsistent mark up in the first verse of a chapter. + first_verse = verses.find(u'versenum') + if first_verse: + verse_list[1] = unicode(first_verse.contents[0]) for verse in verses(u'sup', u'versenum'): raw_verse_num = verse.next clean_verse_num = 0 @@ -251,7 +255,7 @@ class BGExtract(object): if isinstance(part.next, Tag) and part.next.name == u'div': # Run out of verses so stop. break - part = part.next + part = part.next verse_list[clean_verse_num] = unicode(verse_text) if not verse_list: log.debug(u'No content found in the BibleGateway response.') diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 344d11584..67469e063 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -25,14 +25,14 @@ ############################################################################### import logging +import os from PyQt4 import QtCore from openlp.core.lib import Receiver, SettingsManager, translate -from openlp.core.utils import AppLocation +from openlp.core.utils import AppLocation, delete_file from openlp.plugins.bibles.lib import parse_reference from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta - from csvbible import CSVBible from http import HTTPBible from opensong import OpenSongBible @@ -144,6 +144,10 @@ class BibleManager(object): for filename in files: bible = BibleDB(self.parent, path=self.path, file=filename) name = bible.get_name() + # Remove corrupted files. + if name is None: + delete_file(os.path.join(self.path, filename)) + continue log.debug(u'Bible Name: "%s"', name) self.db_cache[name] = bible # Look to see if lazy load bible exists and get create getter. @@ -250,7 +254,7 @@ class BibleManager(object): if not bible: Receiver.send_message(u'openlp_information_message', { u'title': translate('BiblesPlugin.BibleManager', - 'No Bibles available'), + 'No Bibles Available'), u'message': translate('BiblesPlugin.BibleManager', 'There are no Bibles currently installed. Please use the ' 'Import Wizard to install one or more Bibles.') diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index ab7897828..0c1da0aed 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -35,7 +35,7 @@ from openlp.core.lib.ui import UiStrings, add_widget_completer, \ media_item_combo_box, critical_error_message_box from openlp.plugins.bibles.forms import BibleImportForm from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \ - get_reference_match + VerseReferenceList, get_reference_match log = logging.getLogger(__name__) @@ -346,7 +346,7 @@ class BibleMediaItem(MediaManagerItem): self.advancedSearchButton.setEnabled(False) critical_error_message_box( message=translate('BiblePlugin.MediaItem', - 'Bible not fully loaded')) + 'Bible not fully loaded.')) else: self.advancedSearchButton.setEnabled(True) self.adjustComboBox(1, self.chapter_count, self.advancedFromChapter) @@ -449,8 +449,7 @@ class BibleMediaItem(MediaManagerItem): if restore: old_text = unicode(combo.currentText()) combo.clear() - for i in range(range_from, range_to + 1): - combo.addItem(unicode(i)) + combo.addItems([unicode(i) for i in range(range_from, range_to + 1)]) if restore and combo.findText(old_text) != -1: combo.setCurrentIndex(combo.findText(old_text)) @@ -539,8 +538,9 @@ class BibleMediaItem(MediaManagerItem): self.displayResults(bible, second_bible) elif critical_error_message_box( message=translate('BiblePlugin.MediaItem', - 'You cannot combine single and second bible verses. Do you ' - 'want to delete your search results and start a new search?'), + 'You cannot combine single and dual Bible verse search results. ' + 'Do you want to delete your search results and start a new ' + 'search?'), parent=self, question=True) == QtGui.QMessageBox.Yes: self.listView.clear() self.displayResults(bible, second_bible) @@ -635,9 +635,9 @@ class BibleMediaItem(MediaManagerItem): bible_text = u'' old_item = None old_chapter = -1 - raw_footer = [] raw_slides = [] raw_title = [] + verses = VerseReferenceList() for item in items: bitem = self.listView.item(item.row()) book = self._decodeQtObject(bitem, 'book') @@ -654,15 +654,9 @@ class BibleMediaItem(MediaManagerItem): second_permissions = \ self._decodeQtObject(bitem, 'second_permissions') second_text = self._decodeQtObject(bitem, 'second_text') + verses.add(book, chapter, verse, version, copyright, permissions) verse_text = self.formatVerse(old_chapter, chapter, verse) - footer = u'%s (%s %s %s)' % (book, version, copyright, permissions) - if footer not in raw_footer: - raw_footer.append(footer) if second_bible: - footer = u'%s (%s %s %s)' % (book, second_version, - second_copyright, second_permissions) - if footer not in raw_footer: - raw_footer.append(footer) bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text, second_text) raw_slides.append(bible_text.rstrip()) @@ -685,6 +679,12 @@ class BibleMediaItem(MediaManagerItem): start_item = item old_item = item old_chapter = chapter + # Add footer + service_item.raw_footer.append(verses.format_verses()) + if second_bible: + verses.add_version(second_version, second_copyright, + second_permissions) + service_item.raw_footer.append(verses.format_versions()) raw_title.append(self.formatTitle(start_item, item)) # If there are no more items we check whether we have to add bible_text. if bible_text: @@ -704,13 +704,7 @@ class BibleMediaItem(MediaManagerItem): service_item.theme = None else: service_item.theme = self.settings.bible_theme - for slide in raw_slides: - service_item.add_from_text(slide[:30], slide) - if service_item.raw_footer: - for footer in raw_footer: - service_item.raw_footer.append(footer) - else: - service_item.raw_footer = raw_footer + [service_item.add_from_text(slide[:30], slide) for slide in raw_slides] return True def formatTitle(self, start_item, old_item): @@ -749,8 +743,7 @@ class BibleMediaItem(MediaManagerItem): else: verse_range = start_chapter + verse_separator + start_verse + \ range_separator + old_chapter + verse_separator + old_verse - title = u'%s %s (%s)' % (start_book, verse_range, bibles) - return title + return u'%s %s (%s)' % (start_book, verse_range, bibles) def checkTitle(self, item, old_item): """ diff --git a/openlp/plugins/bibles/lib/openlp1.py b/openlp/plugins/bibles/lib/openlp1.py index 03011fa5e..e43417c02 100644 --- a/openlp/plugins/bibles/lib/openlp1.py +++ b/openlp/plugins/bibles/lib/openlp1.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -27,8 +27,6 @@ import logging import sqlite -from PyQt4 import QtCore - from openlp.core.lib import Receiver from openlp.core.ui.wizard import WizardStrings from openlp.plugins.bibles.lib.db import BibleDB diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index 356483986..585ecf9c7 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -25,9 +25,7 @@ ############################################################################### import logging - from lxml import objectify -from PyQt4 import QtCore from openlp.core.lib import Receiver, translate from openlp.plugins.bibles.lib.db import BibleDB diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index 000471b96..e2eb25b4f 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -31,8 +31,6 @@ import chardet import codecs import re -from PyQt4 import QtCore - from openlp.core.lib import Receiver, translate from openlp.core.utils import AppLocation from openlp.plugins.bibles.lib.db import BibleDB diff --git a/openlp/plugins/bibles/lib/versereferencelist.py b/openlp/plugins/bibles/lib/versereferencelist.py new file mode 100644 index 000000000..bc28f2570 --- /dev/null +++ b/openlp/plugins/bibles/lib/versereferencelist.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +class VerseReferenceList(object): + """ + The VerseReferenceList class encapsulates a list of verse references, but + maintains the order in which they were added. + """ + + def __init__(self): + self.verse_list = [] + self.version_list = [] + self.current_index = -1 + + def add(self, book, chapter, verse, version, copyright, permission): + self.add_version(version, copyright, permission) + if not self.verse_list or \ + self.verse_list[self.current_index][u'book'] != book: + self.verse_list.append({u'version': version, u'book': book, + u'chapter': chapter, u'start': verse, u'end': verse}) + self.current_index += 1 + elif self.verse_list[self.current_index][u'chapter'] != chapter: + self.verse_list.append({u'version': version, u'book': book, + u'chapter': chapter, u'start': verse, u'end': verse}) + self.current_index += 1 + elif (self.verse_list[self.current_index][u'end'] + 1) == verse: + self.verse_list[self.current_index][u'end'] = verse + else: + self.verse_list.append({u'version': version, u'book': book, + u'chapter': chapter, u'start': verse, u'end': verse}) + self.current_index += 1 + + def add_version(self, version, copyright, permission): + for bible_version in self.version_list: + if bible_version[u'version'] == version: + return + self.version_list.append({u'version': version, u'copyright': copyright, + u'permission': permission}) + + def format_verses(self): + result = u'' + for index, verse in enumerate(self.verse_list): + if index == 0: + result = u'%s %s:%s' % (verse[u'book'], verse[u'chapter'], + verse[u'start']) + if verse[u'start'] != verse[u'end']: + result = u'%s-%s' % (result, verse[u'end']) + continue + prev = index - 1 + if self.verse_list[prev][u'version'] != verse[u'version']: + result = u'%s (%s)' % (result, self.verse_list[prev][u'version']) + result = result + u', ' + if self.verse_list[prev][u'book'] != verse[u'book']: + result = u'%s%s %s:' % (result, verse[u'book'], + verse[u'chapter']) + elif self.verse_list[prev][u'chapter'] != verse[u'chapter']: + result = u'%s%s:' % (result, verse[u'chapter']) + result = result + str(verse[u'start']) + if verse[u'start'] != verse[u'end']: + result = u'%s-%s' % (result, verse[u'end']) + if len(self.version_list) > 1: + result = u'%s (%s)' % (result, verse[u'version']) + return result + + def format_versions(self): + result = u'' + for index, version in enumerate(self.version_list): + if index > 0: + if result[-1] not in [u';', u',', u'.']: + result = result + u';' + result = result + u' ' + result = u'%s%s, %s' % (result, version[u'version'], + version[u'copyright']) + if version[u'permission'].strip(): + result = result + u', ' + version[u'permission'] + return result diff --git a/openlp/plugins/custom/__init__.py b/openlp/plugins/custom/__init__.py index 3a1e4461a..5171155d2 100644 --- a/openlp/plugins/custom/__init__.py +++ b/openlp/plugins/custom/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/customplugin.py b/openlp/plugins/custom/customplugin.py index c6c129e68..0e88202ca 100644 --- a/openlp/plugins/custom/customplugin.py +++ b/openlp/plugins/custom/customplugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -47,7 +47,7 @@ class CustomPlugin(Plugin): log.info(u'Custom Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Custom', u'1.9.4', plugin_helpers, + Plugin.__init__(self, u'Custom', plugin_helpers, CustomMediaItem, CustomTab) self.weight = -5 self.manager = Manager(u'custom', init_schema) diff --git a/openlp/plugins/custom/forms/__init__.py b/openlp/plugins/custom/forms/__init__.py index c12d29c07..fb3cf975b 100644 --- a/openlp/plugins/custom/forms/__init__.py +++ b/openlp/plugins/custom/forms/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/forms/editcustomdialog.py b/openlp/plugins/custom/forms/editcustomdialog.py index 12ac3ed7e..1ea0413ff 100644 --- a/openlp/plugins/custom/forms/editcustomdialog.py +++ b/openlp/plugins/custom/forms/editcustomdialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index 232cb1e38..f81bd4c7d 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -220,10 +220,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): Removes the current row from the list. """ self.slideListView.takeItem(self.slideListView.currentRow()) - if self.slideListView.currentRow() == 0: - self.upButton.setEnabled(False) - if self.slideListView.currentRow() == self.slideListView.count(): - self.downButton.setEnabled(False) + self.onCurrentRowChanged(self.slideListView.currentRow()) def onCurrentRowChanged(self, row): """ diff --git a/openlp/plugins/custom/forms/editcustomslidedialog.py b/openlp/plugins/custom/forms/editcustomslidedialog.py index 08610954f..d6ebf23ec 100644 --- a/openlp/plugins/custom/forms/editcustomslidedialog.py +++ b/openlp/plugins/custom/forms/editcustomslidedialog.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/forms/editcustomslideform.py b/openlp/plugins/custom/forms/editcustomslideform.py index 2aea81482..24ddc3775 100644 --- a/openlp/plugins/custom/forms/editcustomslideform.py +++ b/openlp/plugins/custom/forms/editcustomslideform.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/lib/__init__.py b/openlp/plugins/custom/lib/__init__.py index 0c53505ac..25abdd38b 100644 --- a/openlp/plugins/custom/lib/__init__.py +++ b/openlp/plugins/custom/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index 9b61f8f15..8ab7ade51 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/lib/customxmlhandler.py b/openlp/plugins/custom/lib/customxmlhandler.py index 5ea941e35..2babe3d12 100644 --- a/openlp/plugins/custom/lib/customxmlhandler.py +++ b/openlp/plugins/custom/lib/customxmlhandler.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/lib/db.py b/openlp/plugins/custom/lib/db.py index 74155ad96..35c24413a 100644 --- a/openlp/plugins/custom/lib/db.py +++ b/openlp/plugins/custom/lib/db.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index c0c7a7e86..69265ed75 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/images/__init__.py b/openlp/plugins/images/__init__.py index 13ea2592a..a375f863f 100644 --- a/openlp/plugins/images/__init__.py +++ b/openlp/plugins/images/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index 84d7a71cc..5d009ad65 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -35,8 +35,7 @@ class ImagePlugin(Plugin): log.info(u'Image Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Images', u'1.9.4', plugin_helpers, - ImageMediaItem) + Plugin.__init__(self, u'Images', plugin_helpers, ImageMediaItem) self.weight = -7 self.icon_path = u':/plugins/plugin_images.png' self.icon = build_icon(self.icon_path) diff --git a/openlp/plugins/images/lib/__init__.py b/openlp/plugins/images/lib/__init__.py index 34c9f1ca8..6a9e364f9 100644 --- a/openlp/plugins/images/lib/__init__.py +++ b/openlp/plugins/images/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index e6fdfe7db..d9b139d68 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/media/__init__.py b/openlp/plugins/media/__init__.py index c13c59ef6..9271a0936 100644 --- a/openlp/plugins/media/__init__.py +++ b/openlp/plugins/media/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/media/lib/__init__.py b/openlp/plugins/media/lib/__init__.py index cb4806631..7f63c8108 100644 --- a/openlp/plugins/media/lib/__init__.py +++ b/openlp/plugins/media/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 40ea7abb1..7612ab7c9 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -24,6 +24,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +from datetime import datetime import logging import os @@ -53,9 +54,6 @@ class MediaMediaItem(MediaManagerItem): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'video_background_replaced'), self.videobackgroundReplaced) - QtCore.QObject.connect(self.mediaObject, - QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'), - self.videoStart) def retranslateUi(self): self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') @@ -124,31 +122,66 @@ class MediaMediaItem(MediaManagerItem): if item is None: return False filename = unicode(item.data(QtCore.Qt.UserRole).toString()) - if os.path.exists(filename): - self.mediaState = None - self.mediaObject.stop() - self.mediaObject.clearQueue() - self.mediaObject.setCurrentSource(Phonon.MediaSource(filename)) - self.mediaObject.play() - service_item.title = unicode(self.plugin.nameStrings[u'singular']) - service_item.add_capability(ItemCapabilities.RequiresMedia) - service_item.add_capability(ItemCapabilities.AllowsVarableStartTime) - # force a nonexistent theme - service_item.theme = -1 - frame = u':/media/image_clapperboard.png' - (path, name) = os.path.split(filename) - while not self.mediaState: - Receiver.send_message(u'openlp_process_events') - service_item.media_length = self.mediaLength - service_item.add_from_command(path, name, frame) - return True - else: + if not os.path.exists(filename): # File is no longer present critical_error_message_box( translate('MediaPlugin.MediaItem', 'Missing Media File'), unicode(translate('MediaPlugin.MediaItem', 'The file %s no longer exists.')) % filename) return False + self.mediaObject.stop() + self.mediaObject.clearQueue() + self.mediaObject.setCurrentSource(Phonon.MediaSource(filename)) + if not self.mediaStateWait(Phonon.StoppedState): + # Due to string freeze, borrow a message from presentations + # This will be corrected in 1.9.6 + critical_error_message_box( + translate('PresentationPlugin.MediaItem', 'Unsupported File'), + unicode(translate('PresentationPlugin.MediaItem', + 'Unsupported File'))) + return False + # File too big for processing + if os.path.getsize(filename) <= 52428800: # 50MiB + self.mediaObject.play() + if not self.mediaStateWait(Phonon.PlayingState) \ + or self.mediaObject.currentSource().type() \ + == Phonon.MediaSource.Invalid: + # Due to string freeze, borrow a message from presentations + # This will be corrected in 1.9.6 + self.mediaObject.stop() + critical_error_message_box( + translate('PresentationPlugin.MediaItem', + 'Unsupported File'), + unicode(translate('PresentationPlugin.MediaItem', + 'Unsupported File'))) + return False + self.mediaLength = self.mediaObject.totalTime() / 1000 + self.mediaObject.stop() + service_item.media_length = self.mediaLength + service_item.add_capability( + ItemCapabilities.AllowsVariableStartTime) + service_item.title = unicode(self.plugin.nameStrings[u'singular']) + service_item.add_capability(ItemCapabilities.RequiresMedia) + # force a non-existent theme + service_item.theme = -1 + frame = u':/media/image_clapperboard.png' + (path, name) = os.path.split(filename) + service_item.add_from_command(path, name, frame) + return True + + def mediaStateWait(self, mediaState): + """ + Wait for the video to change its state + Wait no longer than 5 seconds. + """ + start = datetime.now() + while self.mediaObject.state() != mediaState: + if self.mediaObject.state() == Phonon.ErrorState: + return False + Receiver.send_message(u'openlp_process_events') + if (datetime.now() - start).seconds > 5: + return False + return True def initialise(self): self.listView.clear() @@ -177,12 +210,3 @@ class MediaMediaItem(MediaManagerItem): item_name.setIcon(build_icon(img)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) self.listView.addItem(item_name) - - def videoStart(self, newState, oldState): - """ - Start the video at a predetermined point. - """ - if newState == Phonon.PlayingState: - self.mediaState = newState - self.mediaLength = self.mediaObject.totalTime()/1000 - self.mediaObject.stop() diff --git a/openlp/plugins/media/lib/mediatab.py b/openlp/plugins/media/lib/mediatab.py index 995816860..2679ad64f 100644 --- a/openlp/plugins/media/lib/mediatab.py +++ b/openlp/plugins/media/lib/mediatab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 3438f0279..e01e6846d 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -38,13 +38,27 @@ class MediaPlugin(Plugin): log.info(u'%s MediaPlugin loaded', __name__) def __init__(self, plugin_helpers): - Plugin.__init__(self, u'Media', u'1.9.4', plugin_helpers, + Plugin.__init__(self, u'Media', plugin_helpers, MediaMediaItem, MediaTab) self.weight = -6 self.icon_path = u':/plugins/plugin_media.png' self.icon = build_icon(self.icon_path) # passed with drag and drop messages self.dnd_id = u'Media' + self.additional_extensions = { + u'audio/ac3': [u'.ac3'], + u'audio/flac': [u'.flac'], + u'audio/x-m4a': [u'.m4a'], + u'audio/midi': [u'.mid', u'.midi'], + u'audio/x-mp3': [u'.mp3'], + u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'], + u'audio/qcelp': [u'.qcp'], + u'audio/x-wma': [u'.wma'], + u'audio/x-ms-wma': [u'.wma'], + u'video/x-flv': [u'.flv'], + u'video/x-matroska': [u'.mpv', u'.mkv'], + u'video/x-wmv': [u'.wmv'], + u'video/x-ms-wmv': [u'.wmv']} self.audio_extensions_list = [] self.video_extensions_list = [] mimetypes.init() @@ -65,6 +79,17 @@ class MediaPlugin(Plugin): self.serviceManager.supportedSuffixes(extension[1:]) log.info(u'MediaPlugin: %s extensions: %s' % (mimetype, u' '.join(extensions))) + # Add extensions for this mimetype from self.additional_extensions. + # This hack clears mimetypes' and operating system's shortcomings + # by providing possibly missing extensions. + if mimetype in self.additional_extensions.keys(): + for extension in self.additional_extensions[mimetype]: + ext = u'*%s' % extension + if ext not in list: + list.append(ext) + self.serviceManager.supportedSuffixes(extension[1:]) + log.info(u'MediaPlugin: %s additional extensions: %s' % (mimetype, + u' '.join(self.additional_extensions[mimetype]))) def about(self): about_text = translate('MediaPlugin', 'Media Plugin' diff --git a/openlp/plugins/presentations/__init__.py b/openlp/plugins/presentations/__init__.py index 628816bcf..bf077953a 100644 --- a/openlp/plugins/presentations/__init__.py +++ b/openlp/plugins/presentations/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/presentations/lib/__init__.py b/openlp/plugins/presentations/lib/__init__.py index b5575268a..b41c2f2f6 100644 --- a/openlp/plugins/presentations/lib/__init__.py +++ b/openlp/plugins/presentations/lib/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 48fb85ed3..8166a2258 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 2a552a480..26229aed6 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 4db78f7a5..b86219f42 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -80,7 +80,8 @@ class Controller(object): if self.doc.is_active(): return if not self.doc.is_loaded(): - self.doc.load_presentation() + if not self.doc.load_presentation(): + return if self.is_live: self.doc.start_presentation() if self.doc.slidenumber > 1: diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 4dc9e8f3a..793b0b75d 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -77,7 +77,9 @@ class PowerpointController(PresentationController): """ Loads PowerPoint process """ - self.process = Dispatch(u'PowerPoint.Application') + log.debug(u'start_process') + if not self.process: + self.process = Dispatch(u'PowerPoint.Application') self.process.Visible = True self.process.WindowState = 2 @@ -120,13 +122,14 @@ class PowerpointDocument(PresentationDocument): ``presentation`` The file name of the presentations to run. """ - log.debug(u'LoadPresentation') + log.debug(u'load_presentation') if not self.controller.process or not self.controller.process.Visible: self.controller.start_process() try: self.controller.process.Presentations.Open(self.filepath, False, False, True) except pywintypes.com_error: + log.debug(u'PPT open failed') return False self.presentation = self.controller.process.Presentations( self.controller.process.Presentations.Count) @@ -145,6 +148,7 @@ class PowerpointDocument(PresentationDocument): However, for the moment, we want a physical file since it makes life easier elsewhere. """ + log.debug(u'create_thumbnails') if self.check_thumbnails(): return for num in range(0, self.presentation.Slides.Count): @@ -170,6 +174,7 @@ class PowerpointDocument(PresentationDocument): """ Returns ``True`` if a presentation is loaded. """ + log.debug(u'is_loaded') try: if not self.controller.process.Visible: return False @@ -186,6 +191,7 @@ class PowerpointDocument(PresentationDocument): """ Returns ``True`` if a presentation is currently active. """ + log.debug(u'is_active') if not self.is_loaded(): return False try: @@ -201,6 +207,7 @@ class PowerpointDocument(PresentationDocument): """ Unblanks (restores) the presentation. """ + log.debug(u'unblank_screen') self.presentation.SlideShowSettings.Run() self.presentation.SlideShowWindow.View.State = 1 self.presentation.SlideShowWindow.Activate() @@ -209,12 +216,14 @@ class PowerpointDocument(PresentationDocument): """ Blanks the screen. """ + log.debug(u'blank_screen') self.presentation.SlideShowWindow.View.State = 3 def is_blank(self): """ Returns ``True`` if screen is blank. """ + log.debug(u'is_blank') if self.is_active(): return self.presentation.SlideShowWindow.View.State == 3 else: @@ -224,6 +233,7 @@ class PowerpointDocument(PresentationDocument): """ Stops the current presentation and hides the output. """ + log.debug(u'stop_presentation') self.presentation.SlideShowWindow.View.Exit() if os.name == u'nt': @@ -231,6 +241,7 @@ class PowerpointDocument(PresentationDocument): """ Starts a presentation from the beginning. """ + log.debug(u'start_presentation') #SlideShowWindow measures its size/position by points, not pixels try: dpi = win32ui.GetActiveWindow().GetDC().GetDeviceCaps(88) @@ -253,30 +264,35 @@ class PowerpointDocument(PresentationDocument): """ Returns the current slide number. """ + log.debug(u'get_slide_number') return self.presentation.SlideShowWindow.View.CurrentShowPosition def get_slide_count(self): """ Returns total number of slides. """ + log.debug(u'get_slide_count') return self.presentation.Slides.Count def goto_slide(self, slideno): """ Moves to a specific slide in the presentation. """ + log.debug(u'goto_slide') self.presentation.SlideShowWindow.View.GotoSlide(slideno) def next_step(self): """ Triggers the next effect of slide on the running presentation. """ + log.debug(u'next_step') self.presentation.SlideShowWindow.View.Next() def previous_step(self): """ Triggers the previous slide on the running presentation. """ + log.debug(u'previous_step') self.presentation.SlideShowWindow.View.Previous() def get_slide_text(self, slide_no): diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index 0900d1d9d..94fd05f31 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -84,7 +84,8 @@ class PptviewController(PresentationController): dllpath = os.path.join(self.plugin.pluginManager.basepath, u'presentations', u'lib', u'pptviewlib', u'pptviewlib.dll') self.process = cdll.LoadLibrary(dllpath) - #self.process.SetDebug(1) + if log.isEnabledFor(logging.DEBUG): + self.process.SetDebug(1) def kill(self): """ @@ -140,8 +141,10 @@ class PptviewDocument(PresentationDocument): PPTviewLib creates large BMP's, but we want small PNG's for consistency. Convert them here. """ + log.debug(u'create_thumbnails') if self.check_thumbnails(): return + log.debug(u'create_thumbnails proceeding') for idx in range(self.get_slide_count()): path = u'%s\\slide%s.bmp' % (self.get_temp_folder(), unicode(idx + 1)) diff --git a/openlp/plugins/presentations/lib/pptviewlib/README.TXT b/openlp/plugins/presentations/lib/pptviewlib/README.TXT index 686278729..6cbf18cb0 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/README.TXT +++ b/openlp/plugins/presentations/lib/pptviewlib/README.TXT @@ -1,17 +1,17 @@ PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org) -Copyright (C) 2008 Jonathan Corwin (j@corwin.co.uk) - -This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program, -allowing it to be more easily controlled from another program. +Copyright (C) 2008-2011 Jonathan Corwin (j@corwin.co.uk) -The PowerPoint Viewer must already be installed on the destination machine, and is +This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program, +allowing it to be more easily controlled from another program. + +The PowerPoint Viewer must already be installed on the destination machine, and is freely available at microsoft.com. The full Microsoft Office PowerPoint and PowerPoint Viewer 97 have a COM interface allowing automation. This ability was removed from the 2003+ viewer offerings. -To developers: I am not a C/C++ or Win32 API programmer as you can probably tell. +To developers: I am not a C/C++ or Win32 API programmer as you can probably tell. The code and API of this DLL could certainly do with some tidying up, and the error trapping, where it exists, is very basic. I'll happily accept patches! @@ -28,94 +28,94 @@ This project can be built with the free Microsoft Visual C++ 2008 Express Editio USAGE ----- BOOL CheckInstalled(void); - Returns TRUE if PowerPointViewer is installed. FALSE if not. + Returns TRUE if PowerPointViewer is installed. FALSE if not. int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath); - Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly - and creates preview images of each slide. Note PowerPoint Viewer only allows the - slideshow to be resized whilst it is being loaded. It can be moved at any time however. + Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly + and creates preview images of each slide. Note PowerPoint Viewer only allows the + slideshow to be resized whilst it is being loaded. It can be moved at any time however. - The only way to count the number of slides is to step through the entire show. Therefore - there will be a delay whilst opening large presentations for the first time. - For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken. + The only way to count the number of slides is to step through the entire show. Therefore + there will be a delay whilst opening large presentations for the first time. + For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken. - filename: The PowerPoint file to be opened. Full path - hParentWnd: The window which will become the parent of the slideshow window. - Can be NULL. - rect: The location/dimensions of the slideshow window. - If all properties of this structure are zero, the dimensions of the hParentWnd - are used. - previewpath If specified, the prefix to use for snapshot images of each slide, in the - form: previewpath + n + ".bmp", where n is the slide number. - A file called previewpath + "info.txt" will also be created containing information - about the PPT file, to speed up future openings of the unmodified file. - Note it is up the calling program to directly access these images if they - are required. + filename: The PowerPoint file to be opened. Full path + hParentWnd: The window which will become the parent of the slideshow window. + Can be NULL. + rect: The location/dimensions of the slideshow window. + If all properties of this structure are zero, the dimensions of the hParentWnd + are used. + previewpath If specified, the prefix to use for snapshot images of each slide, in the + form: previewpath + n + ".bmp", where n is the slide number. + A file called previewpath + "info.txt" will also be created containing information + about the PPT file, to speed up future openings of the unmodified file. + Note it is up the calling program to directly access these images if they + are required. + + RETURNS: An unique identifier to pass to other methods in this library. + If < 0, then the PPT failed to open. + If >=0, ClosePPT must be called when the PPT is no longer being used + or when the calling program is closed to release resources/hooks. - RETURNS: An unique identifier to pass to other methods in this library. - If < 0, then the PPT failed to open. - If >=0, ClosePPT must be called when the PPT is no longer being used - or when the calling program is closed to release resources/hooks. - void ClosePPT(int id); - Closes the presentation, releasing any resources and hooks. + Closes the presentation, releasing any resources and hooks. + + id: The value returned from OpenPPT. - id: The value returned from OpenPPT. - int GetCurrentSlide(int id); - Returns the current slide number (from 1) + Returns the current slide number (from 1) - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. int GetSlideCount(int id); - Returns the total number of slides. + Returns the total number of slides. - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. void NextStep(int id); - Advances one step (animation) through the slideshow. + Advances one step (animation) through the slideshow. - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. void PrevStep(int id); - Goes backwards one step (animation) through the slideshow. + Goes backwards one step (animation) through the slideshow. - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. void GotoSlide(int id, int slideno); - Goes directly to a specific slide in the slideshow + Goes directly to a specific slide in the slideshow - id: The value returned from OpenPPT. - slideno: The number of the slide (from 1) to go directly to. - - If the slide has already been displayed, then the completed slide with animations performed - will be shown. This is how the PowerPoint Viewer works so have no control over this. + id: The value returned from OpenPPT. + slideno: The number of the slide (from 1) to go directly to. + + If the slide has already been displayed, then the completed slide with animations performed + will be shown. This is how the PowerPoint Viewer works so have no control over this. void RestartShow(int id); - Restarts the show from the beginning. To reset animations, behind the scenes it - has to travel to the end and step backwards though the entire show. Therefore - for large presentations there might be a delay. + Restarts the show from the beginning. To reset animations, behind the scenes it + has to travel to the end and step backwards though the entire show. Therefore + for large presentations there might be a delay. - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. void Blank(int id); - Blanks the screen, colour black. + Blanks the screen, colour black. - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. void Unblank(int id) - Unblanks the screen, restoring it to it's pre-blank state. - - id: The value returned from OpenPPT. + Unblanks the screen, restoring it to it's pre-blank state. + + id: The value returned from OpenPPT. void Stop(int id) - Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer) + Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer) - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. void Resume(int id) - Moves the slideshow display back onto the screen following a Stop() + Moves the slideshow display back onto the screen following a Stop() - id: The value returned from OpenPPT. + id: The value returned from OpenPPT. diff --git a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py index 1e10def7d..337bdb09f 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py +++ b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -30,19 +30,32 @@ from ctypes import * from ctypes.wintypes import RECT class PPTViewer(QtGui.QWidget): + """ + Standalone Test Harness for the pptviewlib library + """ def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.pptid = -1 self.setWindowTitle(u'PowerPoint Viewer Test') - PPTLabel = QtGui.QLabel(u'Open PowerPoint file') - slideLabel = QtGui.QLabel(u'Go to slide #') - self.PPTEdit = QtGui.QLineEdit() + ppt_label = QtGui.QLabel(u'Open PowerPoint file') + slide_label = QtGui.QLabel(u'Go to slide #') + self.pptEdit = QtGui.QLineEdit() self.slideEdit = QtGui.QLineEdit() + x_label = QtGui.QLabel(u'X pos') + y_label = QtGui.QLabel(u'Y pos') + width_label = QtGui.QLabel(u'Width') + height_label = QtGui.QLabel(u'Height') + self.xEdit = QtGui.QLineEdit(u'100') + self.yEdit = QtGui.QLineEdit(u'100') + self.widthEdit = QtGui.QLineEdit(u'900') + self.heightEdit = QtGui.QLineEdit(u'700') self.total = QtGui.QLabel() - PPTBtn = QtGui.QPushButton(u'Open') - PPTDlgBtn = QtGui.QPushButton(u'...') - slideBtn = QtGui.QPushButton(u'Go') + ppt_btn = QtGui.QPushButton(u'Open') + ppt_dlg_btn = QtGui.QPushButton(u'...') + folder_label = QtGui.QLabel(u'Slide .bmp path') + self.folderEdit = QtGui.QLineEdit(u'slide') + slide_btn = QtGui.QPushButton(u'Go') prev = QtGui.QPushButton(u'Prev') next = QtGui.QPushButton(u'Next') blank = QtGui.QPushButton(u'Blank') @@ -51,122 +64,149 @@ class PPTViewer(QtGui.QWidget): close = QtGui.QPushButton(u'Close') resume = QtGui.QPushButton(u'Resume') stop = QtGui.QPushButton(u'Stop') - pptwindow = QtGui.QWidget() - grid = QtGui.QGridLayout() - grid.addWidget(PPTLabel, 0, 0) - grid.addWidget(self.PPTEdit, 0, 1) - grid.addWidget(PPTDlgBtn, 0, 2) - grid.addWidget(PPTBtn, 0, 3) - grid.addWidget(slideLabel, 1, 0) - grid.addWidget(self.slideEdit, 1, 1) - grid.addWidget(slideBtn, 1, 3) - grid.addWidget(prev, 2, 0) - grid.addWidget(next, 2, 1) - grid.addWidget(blank, 3, 0) - grid.addWidget(unblank, 3, 1) - grid.addWidget(restart, 4, 0) - grid.addWidget(close, 4, 1) - grid.addWidget(stop, 5, 0) - grid.addWidget(resume, 5, 1) - grid.addWidget(pptwindow, 6, 0, 10, 3) - self.connect(PPTBtn, QtCore.SIGNAL(u'clicked()'), self.OpenClick) - self.connect(PPTDlgBtn, QtCore.SIGNAL(u'clicked()'), self.OpenDialog) - self.connect(slideBtn, QtCore.SIGNAL(u'clicked()'), self.GotoClick) - self.connect(prev, QtCore.SIGNAL(u'clicked()'), self.PrevClick) - self.connect(next, QtCore.SIGNAL(u'clicked()'), self.NextClick) - self.connect(blank, QtCore.SIGNAL(u'clicked()'), self.BlankClick) - self.connect(unblank, QtCore.SIGNAL(u'clicked()'), self.UnblankClick) - self.connect(restart, QtCore.SIGNAL(u'clicked()'), self.RestartClick) - self.connect(close, QtCore.SIGNAL(u'clicked()'), self.CloseClick) - self.connect(stop, QtCore.SIGNAL(u'clicked()'), self.StopClick) - self.connect(resume, QtCore.SIGNAL(u'clicked()'), self.ResumeClick) - + row = 0 + grid.addWidget(folder_label, 0, 0) + grid.addWidget(self.folderEdit, 0, 1) + row = row + 1 + grid.addWidget(x_label, row, 0) + grid.addWidget(self.xEdit, row, 1) + grid.addWidget(y_label, row, 2) + grid.addWidget(self.yEdit, row, 3) + row = row + 1 + grid.addWidget(width_label, row, 0) + grid.addWidget(self.widthEdit, row, 1) + grid.addWidget(height_label, row, 2) + grid.addWidget(self.heightEdit, row, 3) + row = row + 1 + grid.addWidget(ppt_label, row, 0) + grid.addWidget(self.pptEdit, row, 1) + grid.addWidget(ppt_dlg_btn, row, 2) + grid.addWidget(ppt_btn, row, 3) + row = row + 1 + grid.addWidget(slide_label, row, 0) + grid.addWidget(self.slideEdit, row, 1) + grid.addWidget(slide_btn, row, 2) + row = row + 1 + grid.addWidget(prev, row, 0) + grid.addWidget(next, row, 1) + row = row + 1 + grid.addWidget(blank, row, 0) + grid.addWidget(unblank, row, 1) + row = row + 1 + grid.addWidget(restart, row, 0) + grid.addWidget(close, row, 1) + row = row + 1 + grid.addWidget(stop, row, 0) + grid.addWidget(resume, row, 1) + self.connect(ppt_btn, QtCore.SIGNAL(u'clicked()'), self.openClick) + self.connect(ppt_dlg_btn, QtCore.SIGNAL(u'clicked()'), self.openDialog) + self.connect(slide_btn, QtCore.SIGNAL(u'clicked()'), self.gotoClick) + self.connect(prev, QtCore.SIGNAL(u'clicked()'), self.prevClick) + self.connect(next, QtCore.SIGNAL(u'clicked()'), self.nextClick) + self.connect(blank, QtCore.SIGNAL(u'clicked()'), self.blankClick) + self.connect(unblank, QtCore.SIGNAL(u'clicked()'), self.unblankClick) + self.connect(restart, QtCore.SIGNAL(u'clicked()'), self.restartClick) + self.connect(close, QtCore.SIGNAL(u'clicked()'), self.closeClick) + self.connect(stop, QtCore.SIGNAL(u'clicked()'), self.stopClick) + self.connect(resume, QtCore.SIGNAL(u'clicked()'), self.resumeClick) self.setLayout(grid) - self.resize(300, 150) - def PrevClick(self): - if self.pptid<0: return - pptdll.PrevStep(self.pptid) - self.UpdateCurrSlide() + def prevClick(self): + if self.pptid < 0: + return + self.pptdll.PrevStep(self.pptid) + self.updateCurrSlide() app.processEvents() - def NextClick(self): - if(self.pptid<0): return - pptdll.NextStep(self.pptid) - self.UpdateCurrSlide() + def nextClick(self): + if self.pptid < 0: + return + self.pptdll.NextStep(self.pptid) + self.updateCurrSlide() app.processEvents() - def BlankClick(self): - if(self.pptid<0): return - pptdll.Blank(self.pptid) + def blankClick(self): + if self.pptid < 0: + return + self.pptdll.Blank(self.pptid) app.processEvents() - def UnblankClick(self): - if(self.pptid<0): return - pptdll.Unblank(self.pptid) + def unblankClick(self): + if self.pptid < 0: + return + self.pptdll.Unblank(self.pptid) app.processEvents() - def RestartClick(self): - if(self.pptid<0): return - pptdll.RestartShow(self.pptid) - self.UpdateCurrSlide() + def restartClick(self): + if self.pptid < 0: + return + self.pptdll.RestartShow(self.pptid) + self.updateCurrSlide() app.processEvents() - def StopClick(self): - if(self.pptid<0): return - pptdll.Stop(self.pptid) + def stopClick(self): + if self.pptid < 0: + return + self.pptdll.Stop(self.pptid) app.processEvents() - def ResumeClick(self): - if(self.pptid<0): return - pptdll.Resume(self.pptid) + def resumeClick(self): + if self.pptid < 0: + return + self.pptdll.Resume(self.pptid) app.processEvents() - def CloseClick(self): - if(self.pptid<0): return - pptdll.ClosePPT(self.pptid) + def closeClick(self): + if self.pptid < 0: + return + self.pptdll.ClosePPT(self.pptid) self.pptid = -1 app.processEvents() - def OpenClick(self): + def openClick(self): oldid = self.pptid; - rect = RECT(100,100,900,700) - filename = unicode(self.PPTEdit.text()) - print filename - self.pptid = pptdll.OpenPPT(filename, None, rect, 'c:\\temp\\slide') - print "id: " + unicode(self.pptid) - if oldid>=0: - pptdll.ClosePPT(oldid); - slides = pptdll.GetSlideCount(self.pptid) - print "slidecount: " + unicode(slides) - self.total.setNum(pptdll.GetSlideCount(self.pptid)) - self.UpdateCurrSlide() + rect = RECT(int(self.xEdit.text()), int(self.yEdit.text()), + int(self.widthEdit.text()), int(self.heightEdit.text())) + filename = str(self.pptEdit.text().replace(u'/', u'\\')) + folder = str(self.folderEdit.text().replace(u'/', u'\\')) + print filename, folder + self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder) + print u'id: ' + unicode(self.pptid) + if oldid >= 0: + self.pptdll.ClosePPT(oldid); + slides = self.pptdll.GetSlideCount(self.pptid) + print u'slidecount: ' + unicode(slides) + self.total.setNum(self.pptdll.GetSlideCount(self.pptid)) + self.updateCurrSlide() - def UpdateCurrSlide(self): - if(self.pptid<0): return - slide = unicode(pptdll.GetCurrentSlide(self.pptid)) - print "currslide: " + slide + def updateCurrSlide(self): + if self.pptid < 0: + return + slide = unicode(self.pptdll.GetCurrentSlide(self.pptid)) + print u'currslide: ' + slide self.slideEdit.setText(slide) app.processEvents() - def GotoClick(self): - if(self.pptid<0): return + def gotoClick(self): + if self.pptid < 0: + return print self.slideEdit.text() - pptdll.GotoSlide(self.pptid, int(self.slideEdit.text())) - self.UpdateCurrSlide() + self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text())) + self.updateCurrSlide() app.processEvents() - def OpenDialog(self): - self.PPTEdit.setText(QtGui.QFileDialog.getOpenFileName(self, 'Open file')) + def openDialog(self): + self.pptEdit.setText(QtGui.QFileDialog.getOpenFileName(self, + u'Open file')) if __name__ == '__main__': - #pptdll = cdll.LoadLibrary(r'C:\Documents and Settings\jonathan\Desktop\pptviewlib.dll') pptdll = cdll.LoadLibrary(r'pptviewlib.dll') pptdll.SetDebug(1) - print "Begin..." + print u'Begin...' app = QtGui.QApplication(sys.argv) - qb = PPTViewer() - qb.show() + window = PPTViewer() + window.pptdll = pptdll + window.show() sys.exit(app.exec_()) diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp index 86876a836..93e7b17d9 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp @@ -1,23 +1,28 @@ -/* - * PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org) - * Copyright (C) 2008 Jonathan Corwin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/****************************************************************************** +* PptViewLib - PowerPoint Viewer 2003/2007 Controller * +* OpenLP - Open Source Lyrics Projection * +* --------------------------------------------------------------------------- * +* Copyright (c) 2008-2011 Raoul Snyman * +* Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael * +* Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, * +* Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, * +* Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund * +* --------------------------------------------------------------------------- * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation; version 2 of the License. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., 59 * +* Temple Place, Suite 330, Boston, MA 02111-1307 USA * +******************************************************************************/ - -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #include #include #include @@ -27,205 +32,224 @@ #include #include "pptviewlib.h" - -// Because of the callbacks used by SetWindowsHookEx, the memory used needs to be -// sharable across processes (the callbacks are done from a different process) -// Therefore use data_seg with RWS memory. +// Because of the callbacks used by SetWindowsHookEx, the memory used needs to +// be sharable across processes (the callbacks are done from a different +// process) Therefore use data_seg with RWS memory. // -// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for alternative -// method of holding memory, removing fixed limits which would allow dynamic number -// of items, rather than a fixed number. Use a Local\ mapping, since global has UAC -// issues in Vista. +// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for +// alternative method of holding memory, removing fixed limits which would allow +// dynamic number of items, rather than a fixed number. Use a Local\ mapping, +// since global has UAC issues in Vista. + #pragma data_seg(".PPTVIEWLIB") -PPTVIEWOBJ pptviewobj[MAX_PPTOBJS] = {NULL}; -HHOOK globalhook = NULL; +PPTVIEW pptView[MAX_PPTS] = {NULL}; +HHOOK globalHook = NULL; BOOL debug = FALSE; #pragma data_seg() #pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS") -#define DEBUG(...) if(debug) printf(__VA_ARGS__) - - HINSTANCE hInstance = NULL; -BOOL APIENTRY DllMain( HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReasonForCall, + LPVOID lpReserved) { hInstance = (HINSTANCE)hModule; - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - DEBUG("PROCESS_ATTACH\n"); - break; - case DLL_THREAD_ATTACH: - DEBUG("THREAD_ATTACH\n"); - break; - case DLL_THREAD_DETACH: - DEBUG("THREAD_DETACH\n"); - break; - case DLL_PROCESS_DETACH: - // Clean up... hopefully there is only the one process attached? - // We'll find out soon enough during tests! - DEBUG("PROCESS_DETACH\n"); - for(int i = 0; i.bmp" will be appended to complete the path. E.g. "c:\temp\slide" would +// ".bmp" will be appended to complete the path. E.g. "c:\temp\slide" would // create "c:\temp\slide1.bmp" slide2.bmp, slide3.bmp etc. // It will also create a *info.txt containing information about the ppt -DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath) +DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, + char *previewPath) { - STARTUPINFO si; - PROCESS_INFORMATION pi; - char cmdline[MAX_PATH * 2]; - int id; + STARTUPINFO si; + PROCESS_INFORMATION pi; + char cmdLine[MAX_PATH * 2]; + int id; - DEBUG("OpenPPT start: %s; %s\n", filename, previewpath); - DEBUG("OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top, rect.left, rect.bottom, rect.right); - if(GetPPTViewerPath(cmdline, sizeof(cmdline))==FALSE) - { - DEBUG("OpenPPT: GetPPTViewerPath failed\n"); - return -1; - } - id = -1; - for(int i = 0; ibottom-wndrect->top; - pptviewobj[id].rect.right = wndrect->right-wndrect->left; - } - else - { - pptviewobj[id].rect.top = rect.top; - pptviewobj[id].rect.left = rect.left; - pptviewobj[id].rect.bottom = rect.bottom; - pptviewobj[id].rect.right = rect.right; - } - strcat_s(cmdline, MAX_PATH * 2, "/F /S \""); - strcat_s(cmdline, MAX_PATH * 2, filename); - strcat_s(cmdline, MAX_PATH * 2, "\""); - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - BOOL gotinfo = GetPPTInfo(id); - /* - * I'd really like to just hook on the new threadid. However this always gives - * error 87. Perhaps I'm hooking to soon? No idea... however can't wait - * since I need to ensure I pick up the WM_CREATE as this is the only - * time the window can be resized in such away the content scales correctly - * - * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId); - */ - if(globalhook!=NULL) - UnhookWindowsHookEx(globalhook); - globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL); - if(globalhook==0) - { - DEBUG("OpenPPT: SetWindowsHookEx failed\n"); - ClosePPT(id); - return -1; - } - pptviewobj[id].state = PPT_STARTED; - Sleep(10); - if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) - { - DEBUG("OpenPPT: CreateProcess failed\n"); - ClosePPT(id); - return -1; - } - pptviewobj[id].dwProcessId = pi.dwProcessId; - pptviewobj[id].dwThreadId = pi.dwThreadId; - pptviewobj[id].hThread = pi.hThread; - pptviewobj[id].hProcess = pi.hProcess; - while(pptviewobj[id].state==PPT_STARTED) - Sleep(10); - if(gotinfo) - { - DEBUG("OpenPPT: Info loaded, no refresh\n"); - pptviewobj[id].state = PPT_LOADED; - Resume(id); - } - else - { - DEBUG("OpenPPT: Get info\n"); - pptviewobj[id].steps = 0; - int steps = 0; - while(pptviewobj[id].state==PPT_OPENED) - { - if(steps<=pptviewobj[id].steps) - { - Sleep(20); - DEBUG("OpenPPT: Step %d/%d\n",steps,pptviewobj[id].steps); - steps++; - NextStep(id); - } - Sleep(10); - } - DEBUG("OpenPPT: Steps %d, first slide steps %d\n",pptviewobj[id].steps,pptviewobj[id].firstSlideSteps); - SavePPTInfo(id); - if(pptviewobj[id].state==PPT_CLOSING||pptviewobj[id].slideCount<=0){ - ClosePPT(id); - id=-1; - } - else - RestartShow(id); - } - if(id>=0) - { - if(pptviewobj[id].mhook!=NULL) - UnhookWindowsHookEx(pptviewobj[id].mhook); - pptviewobj[id].mhook = NULL; - } - DEBUG("OpenPPT: Exit: id=%i\n", id); - return id; + DEBUG("OpenPPT start: %s; %s\n", filename, previewPath); + DEBUG("OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top, + rect.left, rect.bottom, rect.right); + if (GetPPTViewerPath(cmdLine, sizeof(cmdLine)) == FALSE) + { + DEBUG("OpenPPT: GetPPTViewerPath failed\n"); + return -1; + } + id = -1; + for (int i = 0; i < MAX_PPTS; i++) + { + if (pptView[i].state == PPT_CLOSED) + { + id = i; + break; + } + } + if (id < 0) + { + DEBUG("OpenPPT: Too many PPTs\n"); + return -1; + } + memset(&pptView[id], 0, sizeof(PPTVIEW)); + strcpy_s(pptView[id].filename, MAX_PATH, filename); + strcpy_s(pptView[id].previewPath, MAX_PATH, previewPath); + pptView[id].state = PPT_CLOSED; + pptView[id].slideCount = 0; + pptView[id].currentSlide = 0; + pptView[id].firstSlideSteps = 0; + pptView[id].lastSlideSteps = 0; + pptView[id].guess = 0; + pptView[id].hParentWnd = hParentWnd; + pptView[id].hWnd = NULL; + pptView[id].hWnd2 = NULL; + for (int i = 0; i < MAX_SLIDES; i++) + { + pptView[id].slideNos[i] = 0; + } + if (hParentWnd != NULL && rect.top == 0 && rect.bottom == 0 + && rect.left == 0 && rect.right == 0) + { + LPRECT windowRect = NULL; + GetWindowRect(hParentWnd, windowRect); + pptView[id].rect.top = 0; + pptView[id].rect.left = 0; + pptView[id].rect.bottom = windowRect->bottom - windowRect->top; + pptView[id].rect.right = windowRect->right - windowRect->left; + } + else + { + pptView[id].rect.top = rect.top; + pptView[id].rect.left = rect.left; + pptView[id].rect.bottom = rect.bottom; + pptView[id].rect.right = rect.right; + } + strcat_s(cmdLine, MAX_PATH * 2, "/F /S \""); + strcat_s(cmdLine, MAX_PATH * 2, filename); + strcat_s(cmdLine, MAX_PATH * 2, "\""); + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + BOOL gotInfo = GetPPTInfo(id); + /* + * I'd really like to just hook on the new threadid. However this always + * gives error 87. Perhaps I'm hooking to soon? No idea... however can't + * wait since I need to ensure I pick up the WM_CREATE as this is the only + * time the window can be resized in such away the content scales correctly + * + * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId); + */ + if (globalHook != NULL) + { + UnhookWindowsHookEx(globalHook); + } + globalHook = SetWindowsHookEx(WH_CBT, CbtProc, hInstance, NULL); + if (globalHook == 0) + { + DEBUG("OpenPPT: SetWindowsHookEx failed\n"); + ClosePPT(id); + return -1; + } + pptView[id].state = PPT_STARTED; + Sleep(10); + if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) + { + DEBUG("OpenPPT: CreateProcess failed\n"); + ClosePPT(id); + return -1; + } + pptView[id].dwProcessId = pi.dwProcessId; + pptView[id].dwThreadId = pi.dwThreadId; + pptView[id].hThread = pi.hThread; + pptView[id].hProcess = pi.hProcess; + while (pptView[id].state == PPT_STARTED) + Sleep(10); + if (gotInfo) + { + DEBUG("OpenPPT: Info loaded, no refresh\n"); + pptView[id].state = PPT_LOADED; + Resume(id); + } + else + { + DEBUG("OpenPPT: Get info\n"); + pptView[id].steps = 0; + int steps = 0; + while (pptView[id].state == PPT_OPENED) + { + if (steps <= pptView[id].steps) + { + Sleep(20); + DEBUG("OpenPPT: Step %d/%d\n", steps, pptView[id].steps); + steps++; + NextStep(id); + } + Sleep(10); + } + DEBUG("OpenPPT: Slides %d, Steps %d, first slide steps %d\n", + pptView[id].slideCount, pptView[id].steps, + pptView[id].firstSlideSteps); + for(int i = 1; i <= pptView[id].slideCount; i++) + { + DEBUG("OpenPPT: Slide %d = %d\n", i, pptView[id].slideNos[i]); + } + SavePPTInfo(id); + if (pptView[id].state == PPT_CLOSING + || pptView[id].slideCount <= 0) + { + ClosePPT(id); + id=-1; + } + else + { + RestartShow(id); + } + } + if (id >= 0) + { + if (pptView[id].msgHook != NULL) + { + UnhookWindowsHookEx(pptView[id].msgHook); + } + pptView[id].msgHook = NULL; + } + DEBUG("OpenPPT: Exit: id=%i\n", id); + return id; } // Load information about the ppt from an info.txt file. // Format: @@ -236,292 +260,316 @@ DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewp // first slide steps BOOL GetPPTInfo(int id) { - struct _stat filestats; - char info[MAX_PATH]; - FILE* pFile; - char buf[100]; + struct _stat fileStats; + char info[MAX_PATH]; + FILE* pFile; + char buf[100]; - DEBUG("GetPPTInfo: start\n"); - if(_stat(pptviewobj[id].filename, &filestats)!=0) - return FALSE; - sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath); - int err = fopen_s(&pFile, info, "r"); - if(err!=0) - { - DEBUG("GetPPTInfo: file open failed - %d\n", err); - return FALSE; - } - fgets(buf, 100, pFile); // version == 1 - fgets(buf, 100, pFile); - if(filestats.st_mtime!=atoi(buf)) - { - fclose (pFile); - return FALSE; - } - fgets(buf, 100, pFile); - if(filestats.st_size!=atoi(buf)) - { - fclose (pFile); - return FALSE; - } - fgets(buf, 100, pFile); // slidecount - int slidecount = atoi(buf); - fgets(buf, 100, pFile); // first slide steps - int firstslidesteps = atoi(buf); - // check all the preview images still exist - for(int i = 1; i<=slidecount; i++) - { - sprintf_s(info, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, i); - if(GetFileAttributes(info)==INVALID_FILE_ATTRIBUTES) - return FALSE; - } - fclose(pFile); - pptviewobj[id].slideCount = slidecount; - pptviewobj[id].firstSlideSteps = firstslidesteps; - DEBUG("GetPPTInfo: exit ok\n"); - return TRUE; + DEBUG("GetPPTInfo: start\n"); + if (_stat(pptView[id].filename, &fileStats) != 0) + { + return FALSE; + } + sprintf_s(info, MAX_PATH, "%sinfo.txt", pptView[id].previewPath); + int err = fopen_s(&pFile, info, "r"); + if (err != 0) + { + DEBUG("GetPPTInfo: file open failed - %d\n", err); + return FALSE; + } + fgets(buf, 100, pFile); // version == 1 + fgets(buf, 100, pFile); + if (fileStats.st_mtime != atoi(buf)) + { + DEBUG("GetPPTInfo: date changed\n"); + fclose (pFile); + return FALSE; + } + fgets(buf, 100, pFile); + if (fileStats.st_size != atoi(buf)) + { + DEBUG("GetPPTInfo: size changed\n"); + fclose (pFile); + return FALSE; + } + fgets(buf, 100, pFile); // slidecount + int slideCount = atoi(buf); + fgets(buf, 100, pFile); // first slide steps + int firstSlideSteps = atoi(buf); + // check all the preview images still exist + for (int i = 1; i <= slideCount; i++) + { + sprintf_s(info, MAX_PATH, "%s%i.bmp", pptView[id].previewPath, i); + if (GetFileAttributes(info) == INVALID_FILE_ATTRIBUTES) + { + DEBUG("GetPPTInfo: bmp not found\n"); + return FALSE; + } + } + fclose(pFile); + pptView[id].slideCount = slideCount; + pptView[id].firstSlideSteps = firstSlideSteps; + DEBUG("GetPPTInfo: exit ok\n"); + return TRUE; } BOOL SavePPTInfo(int id) { - struct _stat filestats; - char info[MAX_PATH]; - FILE* pFile; + struct _stat fileStats; + char info[MAX_PATH]; + FILE* pFile; - DEBUG("SavePPTInfo: start\n"); - if(_stat(pptviewobj[id].filename, &filestats)!=0) - { - DEBUG("SavePPTInfo: stat of %s failed\n", pptviewobj[id].filename); - return FALSE; - } - sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath); - int err = fopen_s(&pFile, info, "w"); - if(err!=0) - { - DEBUG("SavePPTInfo: fopen of %s failed%i\n", info, err); - return FALSE; - } - fprintf(pFile, "1\n"); - fprintf(pFile, "%u\n", filestats.st_mtime); - fprintf(pFile, "%u\n", filestats.st_size); - fprintf(pFile, "%u\n", pptviewobj[id].slideCount); - fprintf(pFile, "%u\n", pptviewobj[id].firstSlideSteps); - fclose (pFile); - DEBUG("SavePPTInfo: exit ok\n"); - return TRUE; + DEBUG("SavePPTInfo: start\n"); + if (_stat(pptView[id].filename, &fileStats) != 0) + { + DEBUG("SavePPTInfo: stat of %s failed\n", pptView[id].filename); + return FALSE; + } + sprintf_s(info, MAX_PATH, "%sinfo.txt", pptView[id].previewPath); + int err = fopen_s(&pFile, info, "w"); + if (err != 0) + { + DEBUG("SavePPTInfo: fopen of %s failed%i\n", info, err); + return FALSE; + } + fprintf(pFile, "1\n"); + fprintf(pFile, "%u\n", fileStats.st_mtime); + fprintf(pFile, "%u\n", fileStats.st_size); + fprintf(pFile, "%u\n", pptView[id].slideCount); + fprintf(pFile, "%u\n", pptView[id].firstSlideSteps); + fclose(pFile); + DEBUG("SavePPTInfo: exit ok\n"); + return TRUE; } // Get the path of the PowerPoint viewer from the registry -BOOL GetPPTViewerPath(char *pptviewerpath, int strsize) +BOOL GetPPTViewerPath(char *pptViewerPath, int stringSize) { - HKEY hkey; - DWORD dwtype, dwsize; - LRESULT lresult; + HKEY hKey; + DWORD dwType, dwSize; + LRESULT lResult; - DEBUG("GetPPTViewerPath: start\n"); - if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "PowerPointViewer.Show.12\\shell\\Show\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS) - if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS) - if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS) - return FALSE; - dwtype = REG_SZ; - dwsize = (DWORD)strsize; - lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pptviewerpath, &dwsize ); - RegCloseKey(hkey); - if(lresult!=ERROR_SUCCESS) - return FALSE; - pptviewerpath[strlen(pptviewerpath)-4] = '\0'; // remove "%1" from end of key value - DEBUG("GetPPTViewerPath: exit ok\n"); - return TRUE; + DEBUG("GetPPTViewerPath: start\n"); + if ((RegOpenKeyEx(HKEY_CLASSES_ROOT, + "PowerPointViewer.Show.12\\shell\\Show\\command", 0, KEY_READ, &hKey) + != ERROR_SUCCESS) + && (RegOpenKeyEx(HKEY_CLASSES_ROOT, + "Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hKey) + != ERROR_SUCCESS) + && (RegOpenKeyEx(HKEY_CLASSES_ROOT, + "Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hKey) + != ERROR_SUCCESS)) + { + return FALSE; + } + dwType = REG_SZ; + dwSize = (DWORD)stringSize; + lResult = RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)pptViewerPath, + &dwSize); + RegCloseKey(hKey); + if (lResult != ERROR_SUCCESS) + { + return FALSE; + } + // remove "%1" from end of key value + pptViewerPath[strlen(pptViewerPath) - 4] = '\0'; + DEBUG("GetPPTViewerPath: exit ok\n"); + return TRUE; } -// Unhook the Windows hook +// Unhook the Windows hook void Unhook(int id) { - DEBUG("Unhook: start %d\n", id); - if(pptviewobj[id].hook!=NULL) - UnhookWindowsHookEx(pptviewobj[id].hook); - if(pptviewobj[id].mhook!=NULL) - UnhookWindowsHookEx(pptviewobj[id].mhook); - pptviewobj[id].hook = NULL; - pptviewobj[id].mhook = NULL; - DEBUG("Unhook: exit ok\n"); + DEBUG("Unhook: start %d\n", id); + if (pptView[id].hook != NULL) + { + UnhookWindowsHookEx(pptView[id].hook); + } + if (pptView[id].msgHook != NULL) + { + UnhookWindowsHookEx(pptView[id].msgHook); + } + pptView[id].hook = NULL; + pptView[id].msgHook = NULL; + DEBUG("Unhook: exit ok\n"); } // Close the PowerPoint viewer, release resources DllExport void ClosePPT(int id) { - DEBUG("ClosePPT: start%d\n", id); - pptviewobj[id].state = PPT_CLOSED; - Unhook(id); - if(pptviewobj[id].hWnd==0) - TerminateThread(pptviewobj[id].hThread, 0); - else - PostMessage(pptviewobj[id].hWnd, WM_CLOSE, 0, 0); - CloseHandle(pptviewobj[id].hThread); - CloseHandle(pptviewobj[id].hProcess); - memset(&pptviewobj[id], 0, sizeof(PPTVIEWOBJ)); - DEBUG("ClosePPT: exit ok\n"); - return; + DEBUG("ClosePPT: start%d\n", id); + pptView[id].state = PPT_CLOSED; + Unhook(id); + if (pptView[id].hWnd == 0) + { + TerminateThread(pptView[id].hThread, 0); + } + else + { + PostMessage(pptView[id].hWnd, WM_CLOSE, 0, 0); + } + CloseHandle(pptView[id].hThread); + CloseHandle(pptView[id].hProcess); + memset(&pptView[id], 0, sizeof(PPTVIEW)); + DEBUG("ClosePPT: exit ok\n"); + return; } // Moves the show back onto the display DllExport void Resume(int id) { - DEBUG("Resume: %d\n", id); - MoveWindow(pptviewobj[id].hWnd, pptviewobj[id].rect.left, pptviewobj[id].rect.top, - pptviewobj[id].rect.right - pptviewobj[id].rect.left, - pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE); - Unblank(id); + DEBUG("Resume: %d\n", id); + MoveWindow(pptView[id].hWnd, pptView[id].rect.left, + pptView[id].rect.top, + pptView[id].rect.right - pptView[id].rect.left, + pptView[id].rect.bottom - pptView[id].rect.top, TRUE); + Unblank(id); } // Moves the show off the screen so it can't be seen DllExport void Stop(int id) { - DEBUG("Stop:%d\n", id); - MoveWindow(pptviewobj[id].hWnd, -32000, -32000, - pptviewobj[id].rect.right - pptviewobj[id].rect.left, - pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE); + DEBUG("Stop:%d\n", id); + MoveWindow(pptView[id].hWnd, -32000, -32000, + pptView[id].rect.right - pptView[id].rect.left, + pptView[id].rect.bottom - pptView[id].rect.top, TRUE); } // Return the total number of slides DllExport int GetSlideCount(int id) { - DEBUG("GetSlideCount:%d\n", id); - if(pptviewobj[id].state==0) - return -1; - else - return pptviewobj[id].slideCount; + DEBUG("GetSlideCount:%d\n", id); + if (pptView[id].state == 0) + { + return -1; + } + else + { + return pptView[id].slideCount; + } } // Return the number of the slide currently viewing DllExport int GetCurrentSlide(int id) { - DEBUG("GetCurrentSlide:%d\n", id); - if(pptviewobj[id].state==0) - return -1; - else - return pptviewobj[id].currentSlide; + DEBUG("GetCurrentSlide:%d\n", id); + if (pptView[id].state == 0) + { + return -1; + } + else + { + return pptView[id].currentSlide; + } } -// Take a step forwards through the show +// Take a step forwards through the show DllExport void NextStep(int id) { - DEBUG("NextStep:%d\n", id); - if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount) - return; - PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0); + DEBUG("NextStep:%d (%d)\n", id, pptView[id].currentSlide); + if (pptView[id].currentSlide > pptView[id].slideCount) return; + if (pptView[id].currentSlide < pptView[id].slideCount) + { + pptView[id].guess = pptView[id].currentSlide + 1; + } + PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), + 0); } -// Take a step backwards through the show +// Take a step backwards through the show DllExport void PrevStep(int id) { - DEBUG("PrevStep:%d\n", id); - PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0); + DEBUG("PrevStep:%d (%d)\n", id, pptView[id].currentSlide); + if (pptView[id].currentSlide > 1) + { + pptView[id].guess = pptView[id].currentSlide - 1; + } + PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), + 0); } // Blank the show (black screen) DllExport void Blank(int id) -{ - // B just toggles blank on/off. However pressing any key unblanks. - // So send random unmapped letter first (say 'A'), then we can - // better guarantee B will blank instead of trying to guess - // whether it was already blank or not. - DEBUG("Blank:%d\n", id); - HWND h1 = GetForegroundWindow(); - HWND h2 = GetFocus(); - SetForegroundWindow(pptviewobj[id].hWnd); - SetFocus(pptviewobj[id].hWnd); - Sleep(50); // slight pause, otherwise event triggering this call may grab focus back! - keybd_event((int)'A', 0, 0, 0); - keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0); - keybd_event((int)'B', 0, 0, 0); - keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0); - SetForegroundWindow(h1); - SetFocus(h2); - //PostMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'B', 0x00300001); - //PostMessage(pptviewobj[id].hWnd2, WM_CHAR, 'b', 0x00300001); - //PostMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'B', 0xC0300001); +{ + // B just toggles blank on/off. However pressing any key unblanks. + // So send random unmapped letter first (say 'A'), then we can + // better guarantee B will blank instead of trying to guess + // whether it was already blank or not. + DEBUG("Blank:%d\n", id); + HWND h1 = GetForegroundWindow(); + HWND h2 = GetFocus(); + SetForegroundWindow(pptView[id].hWnd); + SetFocus(pptView[id].hWnd); + // slight pause, otherwise event triggering this call may grab focus back! + Sleep(50); + keybd_event((int)'A', 0, 0, 0); + keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0); + keybd_event((int)'B', 0, 0, 0); + keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0); + SetForegroundWindow(h1); + SetFocus(h2); } -// Unblank the show +// Unblank the show DllExport void Unblank(int id) -{ - DEBUG("Unblank:%d\n", id); - // Pressing any key resumes. - // For some reason SendMessage works for unblanking, but not blanking. -// SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'A', 0); - SendMessage(pptviewobj[id].hWnd2, WM_CHAR, 'A', 0); -// SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'A', 0); -// HWND h1 = GetForegroundWindow(); -// HWND h2 = GetFocus(); -// Sleep(50); // slight pause, otherwise event triggering this call may grab focus back! -// SetForegroundWindow(pptviewobj[id].hWnd); -// SetFocus(pptviewobj[id].hWnd); -// keybd_event((int)'A', 0, 0, 0); -// SetForegroundWindow(h1); -// SetFocus(h2); +{ + DEBUG("Unblank:%d\n", id); + // Pressing any key resumes. + // For some reason SendMessage works for unblanking, but not blanking. + SendMessage(pptView[id].hWnd2, WM_CHAR, 'A', 0); } // Go directly to a slide -DllExport void GotoSlide(int id, int slideno) -{ - DEBUG("GotoSlide %i %i:\n", id, slideno); - // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work - // perhaps I was sending to the wrong window? No idea. - // Anyway fall back to keybd_event, which is OK as long we makesure - // the slideshow has focus first - char ch[10]; +DllExport void GotoSlide(int id, int slideNo) +{ + DEBUG("GotoSlide %i %i:\n", id, slideNo); + // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work + // perhaps I was sending to the wrong window? No idea. + // Anyway fall back to keybd_event, which is OK as long we makesure + // the slideshow has focus first + char ch[10]; - if(slideno<0) return; - _itoa_s(slideno, ch, 10, 10); - HWND h1 = GetForegroundWindow(); - HWND h2 = GetFocus(); - SetForegroundWindow(pptviewobj[id].hWnd); - SetFocus(pptviewobj[id].hWnd); - Sleep(50); // slight pause, otherwise event triggering this call may grab focus back! - for(int i=0;i<10;i++) - { - if(ch[i]=='\0') break; - keybd_event((BYTE)ch[i], 0, 0, 0); - keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0); - } - keybd_event(VK_RETURN, 0, 0, 0); - keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0); - SetForegroundWindow(h1); - SetFocus(h2); - - //for(int i=0;i<10;i++) - //{ - // if(ch[i]=='\0') break; - // SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, ch[i], 0); - // SendMessage(pptviewobj[id].hWnd2, WM_CHAR, ch[i], 0); - // SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, ch[i], 0); - //} - //SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, VK_RETURN, 0); - //SendMessage(pptviewobj[id].hWnd2, WM_CHAR, VK_RETURN, 0); - //SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, VK_RETURN, 0); - //keybd_event(VK_RETURN, 0, 0, 0); + if (slideNo < 0) return; + pptView[id].guess = slideNo; + _itoa_s(slideNo, ch, 10, 10); + HWND h1 = GetForegroundWindow(); + HWND h2 = GetFocus(); + SetForegroundWindow(pptView[id].hWnd); + SetFocus(pptView[id].hWnd); + // slight pause, otherwise event triggering this call may grab focus back! + Sleep(50); + for (int i=0; i<10; i++) + { + if (ch[i] == '\0') break; + keybd_event((BYTE)ch[i], 0, 0, 0); + keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0); + } + keybd_event(VK_RETURN, 0, 0, 0); + keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0); + SetForegroundWindow(h1); + SetFocus(h2); } // Restart the show from the beginning DllExport void RestartShow(int id) { - // If we just go direct to slide one, then it remembers that all other slides have - // been animated, so ends up just showing the completed slides of those slides that - // have been animated next time we advance. - // Only way I've found to get around this is to step backwards all the way through. - // Lets move the window out of the way first so the audience doesn't see this. - DEBUG("RestartShow:%d\n", id); - Stop(id); - GotoSlide(id, pptviewobj[id].slideCount); - while(pptviewobj[id].currentSlide>1) - { - PrevStep(id); - Sleep(10); - } - for(int i=0;i<=pptviewobj[id].firstSlideSteps;i++) - { - PrevStep(id); - Sleep(10); - } - Resume(id); + // If we just go direct to slide one, then it remembers that all other + // slides have been animated, so ends up just showing the completed slides + // of those slides that have been animated next time we advance. + // Only way I've found to get around this is to step backwards all the way + // through. Lets move the window out of the way first so the audience + // doesn't see this. + DEBUG("RestartShow:%d\n", id); + Stop(id); + GotoSlide(id, pptView[id].slideCount); + for (int i=0; i <= pptView[id].steps - pptView[id].lastSlideSteps; i++) + { + PrevStep(id); + Sleep(10); + } + int i = 0; + while ((pptView[id].currentSlide > 1) && (i++ < 30000)) + { + Sleep(10); + } + Resume(id); } // This hook is started with the PPTVIEW.EXE process and waits for the @@ -530,234 +578,287 @@ DllExport void RestartShow(int id) // Release the hook as soon as we're complete to free up resources LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam) { - HHOOK hook = globalhook; - if(nCode==HCBT_CREATEWND) + HHOOK hook = globalHook; + if (nCode == HCBT_CREATEWND) { - char csClassName[16]; + char csClassName[16]; HWND hCurrWnd = (HWND)wParam; - DWORD retProcId = NULL; - GetClassName(hCurrWnd, csClassName, sizeof(csClassName)); - if((strcmp(csClassName, "paneClassDC")==0) - ||(strcmp(csClassName, "screenClass")==0)) - { - int id=-1; - DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL); - for(int i=0; i=0) - { - if(strcmp(csClassName, "paneClassDC")==0) - pptviewobj[id].hWnd2=hCurrWnd; - else - { - pptviewobj[id].hWnd=hCurrWnd; - CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam; - if(pptviewobj[id].hParentWnd!=NULL) - cw->lpcs->hwndParent = pptviewobj[id].hParentWnd; - cw->lpcs->cy=(pptviewobj[id].rect.bottom-pptviewobj[id].rect.top); - cw->lpcs->cx=(pptviewobj[id].rect.right-pptviewobj[id].rect.left); - cw->lpcs->y=-32000; - cw->lpcs->x=-32000; - } - if((pptviewobj[id].hWnd!=NULL)&&(pptviewobj[id].hWnd2!=NULL)) - { - UnhookWindowsHookEx(globalhook); - globalhook=NULL; - pptviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pptviewobj[id].dwThreadId); - pptviewobj[id].mhook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInstance,pptviewobj[id].dwThreadId); - Sleep(10); - pptviewobj[id].state = PPT_OPENED; - } - } - } + DWORD retProcId = NULL; + GetClassName(hCurrWnd, csClassName, sizeof(csClassName)); + if ((strcmp(csClassName, "paneClassDC") == 0) + ||(strcmp(csClassName, "screenClass") == 0)) + { + int id = -1; + DWORD windowThread = GetWindowThreadProcessId(hCurrWnd, NULL); + for (int i=0; i < MAX_PPTS; i++) + { + if (pptView[i].dwThreadId == windowThread) + { + id = i; + break; + } + } + if (id >= 0) + { + if (strcmp(csClassName, "paneClassDC") == 0) + { + pptView[id].hWnd2 = hCurrWnd; + } + else + { + pptView[id].hWnd = hCurrWnd; + CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam; + if (pptView[id].hParentWnd != NULL) + { + cw->lpcs->hwndParent = pptView[id].hParentWnd; + } + cw->lpcs->cy = pptView[id].rect.bottom + - pptView[id].rect.top; + cw->lpcs->cx = pptView[id].rect.right + - pptView[id].rect.left; + cw->lpcs->y = -32000; + cw->lpcs->x = -32000; + } + if ((pptView[id].hWnd != NULL) && (pptView[id].hWnd2 != NULL)) + { + UnhookWindowsHookEx(globalHook); + globalHook = NULL; + pptView[id].hook = SetWindowsHookEx(WH_CALLWNDPROC, + CwpProc, hInstance, pptView[id].dwThreadId); + pptView[id].msgHook = SetWindowsHookEx(WH_GETMESSAGE, + GetMsgProc, hInstance, pptView[id].dwThreadId); + Sleep(10); + pptView[id].state = PPT_OPENED; + } + } + } } - return CallNextHookEx(hook,nCode,wParam,lParam); + return CallNextHookEx(hook, nCode, wParam, lParam); } // This hook exists whilst the slideshow is loading but only listens on the // slideshows thread. It listens out for mousewheel events -LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) +LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { - HHOOK hook = NULL; - MSG *pMSG = (MSG *)lParam; - DWORD windowthread = GetWindowThreadProcessId(pMSG->hwnd,NULL); - int id=-1; - for(int i=0; i=0&&nCode==HC_ACTION&&wParam==PM_REMOVE&&pMSG->message==WM_MOUSEWHEEL) + HHOOK hook = NULL; + MSG *pMSG = (MSG *)lParam; + DWORD windowThread = GetWindowThreadProcessId(pMSG->hwnd, NULL); + int id = -1; + for (int i = 0; i < MAX_PPTS; i++) { - if(pptviewobj[id].state!=PPT_LOADED) - { - if(pptviewobj[id].currentSlide==1) - pptviewobj[id].firstSlideSteps++; - pptviewobj[id].steps++; - } + if (pptView[i].dwThreadId == windowThread) + { + id = i; + hook = pptView[id].msgHook; + break; + } + } + if (id >= 0 && nCode == HC_ACTION && wParam == PM_REMOVE + && pMSG->message == WM_MOUSEWHEEL) + { + if (pptView[id].state != PPT_LOADED) + { + if (pptView[id].currentSlide == 1) + { + pptView[id].firstSlideSteps++; + } + pptView[id].steps++; + pptView[id].lastSlideSteps++; + } } return CallNextHookEx(hook, nCode, wParam, lParam); } // This hook exists whilst the slideshow is running but only listens on the // slideshows thread. It listens out for slide changes, message WM_USER+22. LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){ - CWPSTRUCT *cwp; - cwp = (CWPSTRUCT *)lParam; - HHOOK hook = NULL; - char filename[MAX_PATH]; + CWPSTRUCT *cwp; + cwp = (CWPSTRUCT *)lParam; + HHOOK hook = NULL; + char filename[MAX_PATH]; - DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL); - int id=-1; - for(int i=0; i=0)&&(nCode==HC_ACTION)) - { - if(cwp->message==WM_USER+22) - { - if(pptviewobj[id].state != PPT_LOADED) - { - if((pptviewobj[id].currentSlide>0) - && (pptviewobj[id].previewpath!=NULL&&strlen(pptviewobj[id].previewpath)>0)) - { - sprintf_s(filename, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, pptviewobj[id].currentSlide); - CaptureAndSaveWindow(cwp->hwnd, filename); - } - } - if(cwp->wParam==0) - { - if(pptviewobj[id].currentSlide>0) - { - pptviewobj[id].state = PPT_LOADED; - pptviewobj[id].currentSlide = pptviewobj[id].slideCount+1; - } - } - else - { - pptviewobj[id].currentSlide = cwp->wParam - 255; - if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount) - pptviewobj[id].slideCount = pptviewobj[id].currentSlide; - } - } - if((pptviewobj[id].state != PPT_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT)) - pptviewobj[id].state = PPT_CLOSING; - } - return CallNextHookEx(hook,nCode,wParam,lParam); + DWORD windowThread = GetWindowThreadProcessId(cwp->hwnd, NULL); + int id = -1; + for (int i = 0; i < MAX_PPTS; i++) + { + if (pptView[i].dwThreadId == windowThread) + { + id = i; + hook = pptView[id].hook; + break; + } + } + if ((id >= 0) && (nCode == HC_ACTION)) + { + if (cwp->message == WM_USER + 22) + { + if (pptView[id].state != PPT_LOADED) + { + if ((pptView[id].currentSlide > 0) + && (pptView[id].previewPath != NULL + && strlen(pptView[id].previewPath) > 0)) + { + sprintf_s(filename, MAX_PATH, "%s%i.bmp", + pptView[id].previewPath, + pptView[id].currentSlide); + CaptureAndSaveWindow(cwp->hwnd, filename); + } + if (((cwp->wParam == 0) + || (pptView[id].slideNos[1] == cwp->wParam)) + && (pptView[id].currentSlide > 0)) + { + pptView[id].state = PPT_LOADED; + pptView[id].currentSlide = pptView[id].slideCount + 1; + } + else + { + if (cwp->wParam > 0) + { + pptView[id].currentSlide = pptView[id].currentSlide + 1; + pptView[id].slideNos[pptView[id].currentSlide] + = cwp->wParam; + pptView[id].slideCount = pptView[id].currentSlide; + pptView[id].lastSlideSteps = 0; + } + } + } + else + { + if (cwp->wParam > 0) + { + if(pptView[id].guess > 0 + && pptView[id].slideNos[pptView[id].guess] == 0) + { + pptView[id].currentSlide = 0; + } + for(int i = 1; i <= pptView[id].slideCount; i++) + { + if(pptView[id].slideNos[i] == cwp->wParam) + { + pptView[id].currentSlide = i; + break; + } + } + if(pptView[id].currentSlide == 0) + { + pptView[id].slideNos[pptView[id].guess] = cwp->wParam; + pptView[id].currentSlide = pptView[id].guess; + } + pptView[id].guess = 0; + } + } + } + if ((pptView[id].state != PPT_CLOSED) + + &&(cwp->message == WM_CLOSE || cwp->message == WM_QUIT)) + { + pptView[id].state = PPT_CLOSING; + } + } + return CallNextHookEx(hook, nCode, wParam, lParam); } VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename) { - HBITMAP hBmp; - if ((hBmp = CaptureWindow(hWnd)) == NULL) - return; + HBITMAP hBmp; + if ((hBmp = CaptureWindow(hWnd)) == NULL) + { + return; + } + RECT client; + GetClientRect(hWnd, &client); + UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits + UINT uiRemainderForPadding; - RECT client; - GetClientRect (hWnd, &client); - UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits - UINT uiRemainderForPadding; + if ((uiRemainderForPadding = uiBytesPerRow % sizeof(DWORD)) > 0) + uiBytesPerRow += (sizeof(DWORD) - uiRemainderForPadding); - if ((uiRemainderForPadding = uiBytesPerRow % sizeof (DWORD)) > 0) - uiBytesPerRow += (sizeof (DWORD) - uiRemainderForPadding); + UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom; + PBYTE pDataBits; - UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom; - PBYTE pDataBits; + if ((pDataBits = new BYTE[uiBytesPerAllRows]) != NULL) + { + BITMAPINFOHEADER bmi = {0}; + BITMAPFILEHEADER bmf = {0}; - if ((pDataBits = new BYTE [uiBytesPerAllRows]) != NULL) - { - BITMAPINFOHEADER bmi = {0}; - BITMAPFILEHEADER bmf = {0}; + // Prepare to get the data out of HBITMAP: + bmi.biSize = sizeof(bmi); + bmi.biPlanes = 1; + bmi.biBitCount = 24; + bmi.biHeight = client.bottom; + bmi.biWidth = client.right; - // Prepare to get the data out of HBITMAP: - bmi.biSize = sizeof (bmi); - bmi.biPlanes = 1; - bmi.biBitCount = 24; - bmi.biHeight = client.bottom; - bmi.biWidth = client.right; + // Get it: + HDC hDC = GetDC(hWnd); + GetDIBits(hDC, hBmp, 0, client.bottom, pDataBits, (BITMAPINFO*) &bmi, + DIB_RGB_COLORS); + ReleaseDC(hWnd, hDC); - // Get it: - HDC hDC = GetDC (hWnd); - GetDIBits (hDC, hBmp, 0, client.bottom, pDataBits, - (BITMAPINFO*) &bmi, DIB_RGB_COLORS); - ReleaseDC (hWnd, hDC); + // Fill the file header: + bmf.bfOffBits = sizeof(bmf) + sizeof(bmi); + bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows; + bmf.bfType = 0x4D42; - // Fill the file header: - bmf.bfOffBits = sizeof (bmf) + sizeof (bmi); - bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows; - bmf.bfType = 0x4D42; - - // Writing: - FILE* pFile; - int err = fopen_s(&pFile, filename, "wb"); - if (err == 0) - { - fwrite (&bmf, sizeof (bmf), 1, pFile); - fwrite (&bmi, sizeof (bmi), 1, pFile); - fwrite (pDataBits, sizeof (BYTE), uiBytesPerAllRows, pFile); - fclose (pFile); - } - delete [] pDataBits; - } - DeleteObject (hBmp); + // Writing: + FILE* pFile; + int err = fopen_s(&pFile, filename, "wb"); + if (err == 0) + { + fwrite(&bmf, sizeof(bmf), 1, pFile); + fwrite(&bmi, sizeof(bmi), 1, pFile); + fwrite(pDataBits, sizeof(BYTE), uiBytesPerAllRows, pFile); + fclose(pFile); + } + delete [] pDataBits; + } + DeleteObject(hBmp); } -HBITMAP CaptureWindow (HWND hWnd) { - HDC hDC; - BOOL bOk = FALSE; - HBITMAP hImage = NULL; +HBITMAP CaptureWindow(HWND hWnd) +{ + HDC hDC; + BOOL bOk = FALSE; + HBITMAP hImage = NULL; - hDC = GetDC (hWnd); - RECT rcClient; - GetClientRect (hWnd, &rcClient); - if ((hImage = CreateCompatibleBitmap (hDC, rcClient.right, rcClient.bottom)) != NULL) - { - HDC hMemDC; - HBITMAP hDCBmp; + hDC = GetDC(hWnd); + RECT rcClient; + GetClientRect(hWnd, &rcClient); + if ((hImage = CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom)) + != NULL) + { + HDC hMemDC; + HBITMAP hDCBmp; - if ((hMemDC = CreateCompatibleDC (hDC)) != NULL) - { - hDCBmp = (HBITMAP) SelectObject (hMemDC, hImage); - HMODULE hLib = LoadLibrary("User32"); - // PrintWindow works for windows outside displayable area - // but was only introduced in WinXP. BitBlt requires the window to be topmost - // and within the viewable area of the display - if(GetProcAddress(hLib, "PrintWindow")==NULL) - { - SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE); - BitBlt (hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0, 0, SRCCOPY); - SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0, SWP_NOSIZE); - } - else - { - PrintWindow(hWnd, hMemDC, 0); - } - SelectObject (hMemDC, hDCBmp); - DeleteDC (hMemDC); - bOk = TRUE; - } - } - ReleaseDC (hWnd, hDC); - if (! bOk) - { - if (hImage) - { - DeleteObject (hImage); - hImage = NULL; - } - } - return hImage; + if ((hMemDC = CreateCompatibleDC(hDC)) != NULL) + { + hDCBmp = (HBITMAP)SelectObject(hMemDC, hImage); + HMODULE hLib = LoadLibrary("User32"); + // PrintWindow works for windows outside displayable area + // but was only introduced in WinXP. BitBlt requires the window to + // be topmost and within the viewable area of the display + if (GetProcAddress(hLib, "PrintWindow") == NULL) + { + SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE); + BitBlt(hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0, + 0, SRCCOPY); + SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0, + SWP_NOSIZE); + } + else + { + PrintWindow(hWnd, hMemDC, 0); + } + SelectObject(hMemDC, hDCBmp); + DeleteDC(hMemDC); + bOk = TRUE; + } + } + ReleaseDC(hWnd, hDC); + if (!bOk) + { + if (hImage) + { + DeleteObject(hImage); + hImage = NULL; + } + } + return hImage; } diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll index f8a0de0d3..36581e00b 100644 Binary files a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll and b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll differ diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h index 6012b0467..4c98f8bb3 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h @@ -1,55 +1,84 @@ +/****************************************************************************** +* PptViewLib - PowerPoint Viewer 2003/2007 Controller * +* OpenLP - Open Source Lyrics Projection * +* --------------------------------------------------------------------------- * +* Copyright (c) 2008-2011 Raoul Snyman * +* Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael * +* Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, * +* Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, * +* Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund * +* --------------------------------------------------------------------------- * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation; version 2 of the License. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., 59 * +* Temple Place, Suite 330, Boston, MA 02111-1307 USA * +******************************************************************************/ -#define DllExport extern "C" __declspec( dllexport ) +#define DllExport extern "C" __declspec( dllexport ) -enum PPTVIEWSTATE { PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED, PPT_CLOSING}; +#define DEBUG(...) if (debug) printf(__VA_ARGS__) -DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath); +enum PPTVIEWSTATE {PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED, + PPT_CLOSING}; + +DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, + char *previewPath); DllExport BOOL CheckInstalled(); DllExport void ClosePPT(int id); DllExport int GetCurrentSlide(int id); DllExport int GetSlideCount(int id); DllExport void NextStep(int id); DllExport void PrevStep(int id); -DllExport void GotoSlide(int id, int slideno); +DllExport void GotoSlide(int id, int slide_no); DllExport void RestartShow(int id); DllExport void Blank(int id); DllExport void Unblank(int id); DllExport void Stop(int id); DllExport void Resume(int id); -DllExport void SetDebug(BOOL onoff); +DllExport void SetDebug(BOOL onOff); LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam); -BOOL GetPPTViewerPath(char *pptviewerpath, int strsize); -HBITMAP CaptureWindow (HWND hWnd); -VOID SaveBitmap (CHAR* filename, HBITMAP hBmp) ; +BOOL GetPPTViewerPath(char *pptViewerPath, int stringSize); +HBITMAP CaptureWindow(HWND hWnd); +VOID SaveBitmap(CHAR* filename, HBITMAP hBmp) ; VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename); BOOL GetPPTInfo(int id); BOOL SavePPTInfo(int id); - - void Unhook(int id); -#define MAX_PPTOBJS 50 +#define MAX_PPTS 16 +#define MAX_SLIDES 256 -struct PPTVIEWOBJ +struct PPTVIEW { - HHOOK hook; - HHOOK mhook; - HWND hWnd; - HWND hWnd2; - HWND hParentWnd; - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - RECT rect; - int slideCount; - int currentSlide; - int firstSlideSteps; - int steps; - char filename[MAX_PATH]; - char previewpath[MAX_PATH]; - PPTVIEWSTATE state; + HHOOK hook; + HHOOK msgHook; + HWND hWnd; + HWND hWnd2; + HWND hParentWnd; + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; + RECT rect; + int slideCount; + int currentSlide; + int firstSlideSteps; + int lastSlideSteps; + int steps; + int guess; + char filename[MAX_PATH]; + char previewPath[MAX_PATH]; + int slideNos[MAX_SLIDES]; + PPTVIEWSTATE state; }; diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index bd37746c1..3c7bdcc33 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index 7b85eebb4..25ad04f82 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index eb7e714f0..3575bbacd 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -51,7 +51,7 @@ class PresentationPlugin(Plugin): """ log.debug(u'Initialised') self.controllers = {} - Plugin.__init__(self, u'Presentations', u'1.9.4', plugin_helpers) + Plugin.__init__(self, u'Presentations', plugin_helpers) self.weight = -8 self.icon_path = u':/plugins/plugin_presentations.png' self.icon = build_icon(self.icon_path) diff --git a/openlp/plugins/remotes/__init__.py b/openlp/plugins/remotes/__init__.py index b5077f435..6dc3d5cce 100644 --- a/openlp/plugins/remotes/__init__.py +++ b/openlp/plugins/remotes/__init__.py @@ -6,9 +6,9 @@ # --------------------------------------------------------------------------- # # Copyright (c) 2008-2011 Raoul Snyman # # Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # -# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, # -# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon # -# Tibble, Carsten Tinggaard, Frode Woldsund # +# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # @@ -26,4 +26,68 @@ """ The :mod:`remotes` plugin allows OpenLP to be controlled from another machine over a network connection. + +Routes: + +``/`` + Go to the web interface. + +``/files/{filename}`` + Serve a static file. + +``/api/poll`` + Poll to see if there are any changes. Returns a JSON-encoded dict of + any changes that occurred:: + + {"results": {"type": "controller"}} + + Or, if there were no results, False:: + + {"results": False} + +``/api/controller/{live|preview}/{action}`` + Perform ``{action}`` on the live or preview controller. Valid actions + are: + + ``next`` + Load the next slide. + + ``previous`` + Load the previous slide. + + ``jump`` + Jump to a specific slide. Requires an id return in a JSON-encoded + dict like so:: + + {"request": {"id": 1}} + + ``first`` + Load the first slide. + + ``last`` + Load the last slide. + + ``text`` + Request the text of the current slide. + +``/api/service/{action}`` + Perform ``{action}`` on the service manager (e.g. go live). Data is + passed as a json-encoded ``data`` parameter. Valid actions are: + + ``next`` + Load the next item in the service. + + ``previous`` + Load the previews item in the service. + + ``jump`` + Jump to a specific item in the service. Requires an id returned in + a JSON-encoded dict like so:: + + {"request": {"id": 1}} + + ``list`` + Request a list of items in the service. + + """ diff --git a/openlp/plugins/remotes/html/images/ajax-loader.png b/openlp/plugins/remotes/html/images/ajax-loader.png new file mode 100644 index 000000000..811a2cdd1 Binary files /dev/null and b/openlp/plugins/remotes/html/images/ajax-loader.png differ diff --git a/openlp/plugins/remotes/html/images/form-check-off.png b/openlp/plugins/remotes/html/images/form-check-off.png new file mode 100644 index 000000000..54e2fe0f8 Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-check-off.png differ diff --git a/openlp/plugins/remotes/html/images/form-check-on.png b/openlp/plugins/remotes/html/images/form-check-on.png new file mode 100644 index 000000000..e6daaaf8b Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-check-on.png differ diff --git a/openlp/plugins/remotes/html/images/form-radio-off.png b/openlp/plugins/remotes/html/images/form-radio-off.png new file mode 100644 index 000000000..32bd43392 Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-radio-off.png differ diff --git a/openlp/plugins/remotes/html/images/form-radio-on.png b/openlp/plugins/remotes/html/images/form-radio-on.png new file mode 100644 index 000000000..ddc404970 Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-radio-on.png differ diff --git a/openlp/plugins/remotes/html/images/icon-search-black.png b/openlp/plugins/remotes/html/images/icon-search-black.png new file mode 100644 index 000000000..5721120f8 Binary files /dev/null and b/openlp/plugins/remotes/html/images/icon-search-black.png differ diff --git a/openlp/plugins/remotes/html/images/icons-18-black.png b/openlp/plugins/remotes/html/images/icons-18-black.png new file mode 100644 index 000000000..3657baea8 Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-18-black.png differ diff --git a/openlp/plugins/remotes/html/images/icons-18-white.png b/openlp/plugins/remotes/html/images/icons-18-white.png new file mode 100644 index 000000000..ccca7b44b Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-18-white.png differ diff --git a/openlp/plugins/remotes/html/images/icons-36-black.png b/openlp/plugins/remotes/html/images/icons-36-black.png new file mode 100644 index 000000000..79b6d601b Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-36-black.png differ diff --git a/openlp/plugins/remotes/html/images/icons-36-white.png b/openlp/plugins/remotes/html/images/icons-36-white.png new file mode 100644 index 000000000..e1b9c04ea Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-36-white.png differ diff --git a/openlp/plugins/remotes/html/images/ui-icon-blank.png b/openlp/plugins/remotes/html/images/ui-icon-blank.png new file mode 100644 index 000000000..a685fe537 Binary files /dev/null and b/openlp/plugins/remotes/html/images/ui-icon-blank.png differ diff --git a/openlp/plugins/remotes/html/images/ui-icon-unblank.png b/openlp/plugins/remotes/html/images/ui-icon-unblank.png new file mode 100644 index 000000000..590361f44 Binary files /dev/null and b/openlp/plugins/remotes/html/images/ui-icon-unblank.png differ diff --git a/openlp/plugins/remotes/html/index.html b/openlp/plugins/remotes/html/index.html index 94bb24d32..3708db654 100644 --- a/openlp/plugins/remotes/html/index.html +++ b/openlp/plugins/remotes/html/index.html @@ -1,57 +1,97 @@ - - - - - OpenLP Remote Controller - - - - + + + + + + OpenLP 2.0 Remote + + + + + -

OpenLP Controller

-

Quick Links: Service Manager | Slide Controller | Miscellaneous

-

Service Manager

-
-

(Click service item to go live.)

-
- Controls -
- -
-
- - -
-
-
-

Slide Controller

-
-

(Click verse to display.)

-
- Controls -
- -
-
- - -
-
-
-

Miscellaneous

-
- - +
+
+

OpenLP 2.0 Remote

+
+
+ -
- - - +
+
+
+
+ Back +

Service Manager

+
+
+
    +
+
+ +
+
+
+ Back +

Slide Controller

+
+
+
    +
+
+ +
+
+
+ Back +

Alerts

+
+
+
+ +
-
- OpenLP website + Show Alert +
+
- diff --git a/openlp/plugins/remotes/html/jquery.js b/openlp/plugins/remotes/html/jquery.js index 7c2430802..14fd6470f 100644 --- a/openlp/plugins/remotes/html/jquery.js +++ b/openlp/plugins/remotes/html/jquery.js @@ -1,154 +1,16 @@ /*! - * jQuery JavaScript Library v1.4.2 + * jQuery JavaScript Library v1.5.1 * http://jquery.com/ * - * Copyright 2010, John Resig + * Copyright 2011, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation + * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * - * Date: Sat Feb 13 22:33:48 2010 -0500 + * Date: Wed Feb 23 13:55:29 2011 -0500 */ -(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); +(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;ic)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="
a";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(c,null,null,[a]).length>0})}(),function(){var a=c.createElement("div");a.innerHTML="
";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(var g=c;g0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div
","
"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1>");try{for(var c=0,e=this.length;c1&&l0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]===""&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("
").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b
";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window); \ No newline at end of file diff --git a/openlp/plugins/remotes/html/jquery.mobile.css b/openlp/plugins/remotes/html/jquery.mobile.css new file mode 100644 index 000000000..6324793f8 --- /dev/null +++ b/openlp/plugins/remotes/html/jquery.mobile.css @@ -0,0 +1,16 @@ +/*! + * jQuery Mobile v1.0a3 + * http://jquerymobile.com/ + * + * Copyright 2010, jQuery Project + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ +/*! + * jQuery Mobile v1.0a3 + * http://jquerymobile.com/ + * + * Copyright 2010, jQuery Project + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */.ui-bar-a{border:1px solid #2a2a2a;background:#111;color:#fff;font-weight:bold;text-shadow:0 -1px 1px #000;background-image:-moz-linear-gradient(top,#3c3c3c,#111);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#3c3c3c),color-stop(1,#111));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#3c3c3c', EndColorStr='#111111')"}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a .ui-link{color:#7cc4e7;font-weight:bold}.ui-body-a{border:1px solid #2a2a2a;background:#222;color:#fff;text-shadow:0 1px 0 #000;font-weight:normal;background-image:-moz-linear-gradient(top,#666,#222);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#666),color-stop(1,#222));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#666666', EndColorStr='#222222)')"}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:bold}.ui-br{border-bottom:1px solid rgba(130,130,130,.3)}.ui-btn-up-a{border:1px solid #222;background:#333;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 -1px 1px #000;text-decoration:none;background-image:-moz-linear-gradient(top,#555,#333);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555),color-stop(1,#333));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#555555', EndColorStr='#333333')"}.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #000;text-decoration:none;background-image:-moz-linear-gradient(top,#666,#444);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#666),color-stop(1,#444));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#666666', EndColorStr='#444444')"}.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#3d3d3d;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #000;background-image:-moz-linear-gradient(top,#333,#5a5a5a);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#333),color-stop(1,#5a5a5a));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#333333', EndColorStr='#5a5a5a')"}.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:bold;text-shadow:0 -1px 1px #254f7a;background-image:-moz-linear-gradient(top,#81a8ce,#5e87b0);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#81a8ce),color-stop(1,#5e87b0));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#81a8ce', EndColorStr='#5e87b0')"}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b .ui-link{color:#7cc4e7;font-weight:bold}.ui-body-b{border:1px solid #c6c6c6;background:#ccc;color:#333;text-shadow:0 1px 0 #fff;font-weight:normal;background-image:-moz-linear-gradient(top,#e6e6e6,#ccc);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e6e6e6),color-stop(1,#ccc));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#e6e6e6', EndColorStr='#cccccc')"}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:bold}.ui-btn-up-b{border:1px solid #145072;background:#2567ab;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 -1px 1px #145072;text-decoration:none;background-image:-moz-linear-gradient(top,#4e89c5,#2567ab);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#5f9cc5),color-stop(1,#396b9e));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#4e89c5', EndColorStr='#2567ab')"}.ui-btn-up-b a.ui-link-inherit{color:#fff}.ui-btn-hover-b{border:1px solid #00516e;background:#4b88b6;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #014d68;background-image:-moz-linear-gradient(top,#72b0d4,#4b88b6);text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#72b0d4),color-stop(1,#4b88b6));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#72b0d4', EndColorStr='#4b88b6')"}.ui-btn-hover-b a.ui-link-inherit{color:#fff}.ui-btn-down-b{border:1px solid #225377;background:#4e89c5;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #225377;background-image:-moz-linear-gradient(top,#396b9e,#4e89c5);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#396b9e),color-stop(1,#4e89c5));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#396b9e', EndColorStr='#4e89c5')"}.ui-btn-down-b a.ui-link-inherit{color:#fff}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{font-family:Helvetica,Arial,sans-serif}.ui-bar-c{border:1px solid #b3b3b3;background:#e9eaeb;color:#3e3e3e;font-weight:bold;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#f0f0f0,#e9eaeb);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#f0f0f0),color-stop(1,#e9eaeb));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#f0f0f0', EndColorStr='#e9eaeb')"}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c{border:1px solid #b3b3b3;color:#333;text-shadow:0 1px 0 #fff;background:#f0f0f0;background-image:-moz-linear-gradient(top,#eee,#ddd);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(1,#ddd));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#dddddd')"}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c .ui-link-inherit{color:#333}.ui-body-c .ui-link{color:#2489ce;font-weight:bold}.ui-btn-up-c{border:1px solid #ccc;background:#eee;font-weight:bold;color:#444;cursor:pointer;text-shadow:0 1px 1px #f6f6f6;text-decoration:none;background-image:-moz-linear-gradient(top,#fefefe,#eee);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fdfdfd),color-stop(1,#eee));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#fdfdfd', EndColorStr='#eeeeee')"}.ui-btn-up-c a.ui-link-inherit{color:#2f3e46}.ui-btn-hover-c{border:1px solid #bbb;background:#dadada;font-weight:bold;color:#101010;text-decoration:none;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#ededed,#dadada);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ededed),color-stop(1,#dadada));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#ededed', EndColorStr='#dadada')"}.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46}.ui-btn-down-c{border:1px solid #808080;background:#fdfdfd;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#eee,#fdfdfd);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(1,#fdfdfd));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#fdfdfd')"}.ui-btn-down-c a.ui-link-inherit{color:#2f3e46}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{font-family:Helvetica,Arial,sans-serif}.ui-bar-d{border:1px solid #ccc;background:#bbb;color:#333;text-shadow:0 1px 0 #eee;background-image:-moz-linear-gradient(top,#ddd,#bbb);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ddd),color-stop(1,#bbb));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#dddddd', EndColorStr='#bbbbbb')"}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-d .ui-link-inherit{color:#333}.ui-bar-d .ui-link{color:#2489ce;font-weight:bold}.ui-body-d{border:1px solid #ccc;color:#333;text-shadow:0 1px 0 #fff;background:#fff}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif}.ui-body-d .ui-link-inherit{color:#333}.ui-body-d .ui-link{color:#2489ce;font-weight:bold}.ui-btn-up-d{border:1px solid #ccc;background:#fff;font-weight:bold;color:#444;text-decoration:none;text-shadow:0 1px 1px #fff}.ui-btn-up-d a.ui-link-inherit{color:#333}.ui-btn-hover-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#222;cursor:pointer;text-shadow:0 1px 1px #fff;text-decoration:none;background-image:-moz-linear-gradient(top,#fdfdfd,#eee);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fdfdfd),color-stop(1,#eee));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#fdfdfd', EndColorStr='#eeeeee')"}.ui-btn-hover-d a.ui-link-inherit{color:#222}.ui-btn-down-d{border:1px solid #aaa;background:#fff;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#eee,#fff);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(1,#fff));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#ffffff')"}.ui-btn-down-d a.ui-link-inherit{border:1px solid #808080;background:#ced0d2;font-weight:bold;color:#111;text-shadow:none;background-image:-moz-linear-gradient(top,#ccc,#eee);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ccc),color-stop(1,#eee));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#cccccc', EndColorStr='#eeeeee')"}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif}.ui-bar-e{border:1px solid #f7c942;background:#fadb4e;color:#333;text-shadow:0 1px 0 #fff;background-image:-moz-linear-gradient(top,#fceda7,#fadb4e);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fceda7),color-stop(1,#fadb4e));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#fceda7', EndColorStr='#fadb4e')"}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-e .ui-link-inherit{color:#333}.ui-bar-e .ui-link{color:#2489ce;font-weight:bold}.ui-body-e{border:1px solid #f7c942;color:#333;text-shadow:0 1px 0 #fff;background:#faeb9e;background-image:-moz-linear-gradient(top,#fff,#faeb9e);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(1,#faeb9e));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#faeb9e')"}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif}.ui-body-e .ui-link-inherit{color:#333}.ui-body-e .ui-link{color:#2489ce;font-weight:bold}.ui-btn-up-e{border:1px solid #f7c942;background:#fadb4e;font-weight:bold;color:#333;cursor:pointer;text-shadow:0 1px 1px #fe3;text-decoration:none;text-shadow:0 1px 0 #fff;background-image:-moz-linear-gradient(top,#fceda7,#fadb4e);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fceda7),color-stop(1,#fadb4e));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#fceda7', EndColorStr='#fadb4e')"}.ui-btn-up-e a.ui-link-inherit{color:#333}.ui-btn-hover-e{border:1px solid #e79952;background:#fbe26f;font-weight:bold;color:#111;text-decoration:none;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#fcf0b5,#fbe26f);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fcf0b5),color-stop(1,#fbe26f));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#fcf0b5', EndColorStr='#fbe26f')"}.ui-btn-hover-e a.ui-link-inherit{color:#333}.ui-btn-down-e{border:1px solid #f7c942;background:#fceda7;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#fadb4e,#fceda7);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fadb4e),color-stop(1,#fceda7));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#fadb4e', EndColorStr='#fceda7')"}.ui-btn-down-e a.ui-link-inherit{color:#333}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif}a.ui-link-inherit{text-decoration:none!important}.ui-btn-active{border:1px solid #155678;background:#4596ce;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 -1px 1px #145072;text-decoration:none;background-image:-moz-linear-gradient(top,#85bae4,#5393c5);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#85bae4),color-stop(1,#5393c5));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#85bae4', EndColorStr='#5393c5')";outline:0}.ui-btn-active a.ui-link-inherit{color:#fff}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3)}.ui-corner-tl{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em}.ui-corner-tr{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bl{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-br{-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-top{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bottom{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-right{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-left{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-all{-moz-border-radius:.6em;-webkit-border-radius:.6em;border-radius:.6em}.ui-disabled{opacity:.3}.ui-disabled,.ui-disabled a{cursor:default!important}.ui-icon{background-image:url(images/icons-18-white.png);background-repeat:no-repeat;background-color:#666;background-color:rgba(0,0,0,.4);-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-disc{background-color:#666;background-color:rgba(0,0,0,.3);-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-black{background-image:url(images/icons-18-black.png)}.ui-icon-black-disc{background-color:#fff;background-color:rgba(255,255,255,.3);-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}@media screen and (-webkit-min-device-pixel-ratio:2),screen and (max--moz-device-pixel-ratio:2){.ui-icon{background-image:url(images/icons-36-white.png);background-size:630px 18px}.ui-icon-black{background-image:url(images/icons-36-black.png)}}.ui-icon-plus{background-position:-0 0}.ui-icon-minus{background-position:-36px 0}.ui-icon-delete{background-position:-72px 0}.ui-icon-arrow-r{background-position:-108px 0}.ui-icon-arrow-l{background-position:-144px 0}.ui-icon-arrow-u{background-position:-180px 0}.ui-icon-arrow-d{background-position:-216px 0}.ui-icon-check{background-position:-252px 0}.ui-icon-gear{background-position:-288px 0}.ui-icon-refresh{background-position:-324px 0}.ui-icon-forward{background-position:-360px 0}.ui-icon-back{background-position:-396px 0}.ui-icon-grid{background-position:-432px 0}.ui-icon-star{background-position:-468px 0}.ui-icon-alert{background-position:-504px 0}.ui-icon-info{background-position:-540px 0}.ui-icon-home{background-position:-576px 0}.ui-icon-search{background-position:-612px 0}.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-color:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;background-size:20px 20px}.ui-icon-checkbox-off{background-image:url(images/form-check-off.png)}.ui-icon-checkbox-on{background-image:url(images/form-check-on.png)}.ui-icon-radio-off{background-image:url(images/form-radio-off.png)}.ui-icon-radio-on{background-image:url(images/form-radio-on.png)}.ui-icon-searchfield{background-image:url(images/icon-search-black.png);background-size:16px 16px}.ui-icon-loading{background-image:url(images/ajax-loader.png);width:40px;height:40px;-moz-border-radius:20px;-webkit-border-radius:20px;border-radius:20px;background-size:35px 35px}.ui-btn-corner-tl{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em}.ui-btn-corner-tr{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bl{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-br{-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-top{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bottom{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-right{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-left{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-all{-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em}.ui-corner-tl,.ui-corner-tr,.ui-corner-bl,.ui-corner-br,.ui-corner-top,.ui-corner-bottom,.ui-corner-right,.ui-corner-left,.ui-corner-all,.ui-btn-corner-tl,.ui-btn-corner-tr,.ui-btn-corner-bl,.ui-btn-corner-br,.ui-btn-corner-top,.ui-btn-corner-bottom,.ui-btn-corner-right,.ui-btn-corner-left,.ui-btn-corner-all{-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.ui-overlay{background:#666;opacity:.5;filter:Alpha(Opacity=50);position:absolute;width:100%;height:100%}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-shadow{-moz-box-shadow:0 1px 4px rgba(0,0,0,.3);-webkit-box-shadow:0 1px 4px rgba(0,0,0,.3);box-shadow:0 1px 4px rgba(0,0,0,.3)}.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2)}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4);box-shadow:0 1px 0 rgba(255,255,255,.4)}.ui-focus{-moz-box-shadow:0 0 12px #387bbe;-webkit-box-shadow:0 0 12px #387bbe;box-shadow:0 0 12px #387bbe}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}.ui-mobile-nosupport-boxshadow .ui-focus{outline-width:2px}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border:0}.ui-mobile-viewport{margin:0;overflow-x:hidden;-webkit-text-size-adjust:none;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-mobile .ui-page-active{display:block;overflow:visible}.portrait,.portrait .ui-page{min-height:480px}.landscape,.landscape .ui-page{min-height:320px}.ui-loading .ui-mobile-viewport{overflow:hidden!important}.ui-loading .ui-loader{display:block}.ui-loading .ui-page{overflow:hidden}.ui-loader{display:none;position:absolute;opacity:.85;z-index:10;left:50%;width:200px;margin-left:-130px;margin-top:-35px;padding:10px 30px}.ui-loader h1{font-size:15px;text-align:center}.ui-loader .ui-icon{position:static;display:block;opacity:.9;margin:0 auto;width:35px;height:35px;background-color:transparent}.ui-mobile-rendering>*{visibility:hidden}.ui-bar,.ui-body{position:relative;padding:.4em 15px;overflow:hidden;display:block;clear:both}.ui-bar{font-size:16px;margin:0}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:16px;display:inline-block}.ui-header,.ui-footer{display:block}.ui-page .ui-header,.ui-page .ui-footer{position:relative}.ui-header .ui-btn-left{position:absolute;left:10px;top:.4em}.ui-header .ui-title,.ui-footer .ui-title{text-align:center;font-size:16px;display:block;margin:.6em 90px .8em;padding:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-header .ui-btn-right{position:absolute;right:10px;top:.4em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-page-fullscreen .ui-content{padding:0}.ui-icon{width:18px;height:18px}.ui-fullscreen img{max-width:100%}.ui-nojs{position:absolute;left:-9999px}.spin{-webkit-transform:rotate(360deg);-webkit-animation-name:spin;-webkit-animation-duration:1s;-webkit-animation-iteration-count:infinite}@-webkit-keyframes spin{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}.in,.out{-webkit-animation-timing-function:ease-in-out;-webkit-animation-duration:350ms}.slide.in{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromright}.slide.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft}.slide.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromleft}.slide.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;z-index:10}.slideup.out{-webkit-animation-name:dontmove;z-index:0}.slideup.out.reverse{-webkit-transform:translateY(100%);z-index:10;-webkit-animation-name:slideouttobottom}.slideup.in.reverse{z-index:0;-webkit-animation-name:dontmove}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;z-index:10}.slidedown.out{-webkit-animation-name:dontmove;z-index:0}.slidedown.out.reverse{-webkit-transform:translateY(-100%);z-index:10;-webkit-animation-name:slideouttotop}.slidedown.in.reverse{z-index:0;-webkit-animation-name:dontmove}@-webkit-keyframes slideinfromright{from{-webkit-transform:translateX(100%)}to{-webkit-transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translateX(-100%)}to{-webkit-transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(100%)}}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.in{opacity:1;z-index:10;-webkit-animation-name:fadein}.fade.out{z-index:0;-webkit-animation-name:fadeout}.ui-mobile-viewport-perspective{-webkit-perspective:1000;position:absolute}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden}.flip{-webkit-animation-duration:.65s;-webkit-backface-visibility:hidden;-webkit-transform:translateX(0)}.flip.in{-webkit-transform:rotateY(0) scale(1);-webkit-animation-name:flipinfromleft}.flip.out{-webkit-transform:rotateY(-180deg) scale(.8);-webkit-animation-name:flipouttoleft}.flip.in.reverse{-webkit-transform:rotateY(0) scale(1);-webkit-animation-name:flipinfromright}.flip.out.reverse{-webkit-transform:rotateY(180deg) scale(.8);-webkit-animation-name:flipouttoright}@-webkit-keyframes flipinfromright{from{-webkit-transform:rotateY(-180deg) scale(.8)}to{-webkit-transform:rotateY(0) scale(1)}}@-webkit-keyframes flipinfromleft{from{-webkit-transform:rotateY(180deg) scale(.8)}to{-webkit-transform:rotateY(0) scale(1)}}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0) scale(1)}to{-webkit-transform:rotateY(-180deg) scale(.8)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0) scale(1)}to{-webkit-transform:rotateY(180deg) scale(.8)}}@-webkit-keyframes dontmove{from{opacity:1}to{opacity:1}}.pop{-webkit-transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);opacity:1;-webkit-animation-name:popin;z-index:10}.pop.out.reverse{-webkit-transform:scale(.2);opacity:0;-webkit-animation-name:popout;z-index:10}.pop.in.reverse{z-index:0;-webkit-animation-name:dontmove}@-webkit-keyframes popin{from{-webkit-transform:scale(.2);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.2);opacity:0}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left}.ui-grid-a .ui-block-a,.ui-grid-a .ui-block-b{width:50%}.ui-grid-a .ui-block-a{clear:left}.ui-grid-b .ui-block-a,.ui-grid-b .ui-block-b,.ui-grid-b .ui-block-c{width:33.333%}.ui-grid-b .ui-block-a{clear:left}.ui-grid-c .ui-block-a,.ui-grid-c .ui-block-b,.ui-grid-c .ui-block-c,.ui-grid-c .ui-block-d{width:25%}.ui-grid-c .ui-block-a{clear:left}.ui-grid-d .ui-block-a,.ui-grid-d .ui-block-b,.ui-grid-d .ui-block-c,.ui-grid-d .ui-block-d,.ui-grid-d .ui-block-e{width:20%}.ui-grid-d .ui-block-a{clear:left}.ui-header,.ui-footer,.ui-page-fullscreen .ui-header,.ui-page-fullscreen .ui-footer{position:absolute;overflow:hidden;width:100%;border-left-width:0;border-right-width:0}.ui-header-fixed,.ui-footer-fixed{z-index:1000;-webkit-transform:translateZ(0)}.ui-footer-duplicate,.ui-page-fullscreen .ui-fixed-inline{display:none}.ui-page-fullscreen .ui-header,.ui-page-fullscreen .ui-footer{opacity:.9}.ui-navbar{overflow:hidden}.ui-navbar ul,.ui-navbar-expanded ul{list-style:none;padding:0;margin:0;position:relative;display:block;border:0}.ui-navbar-collapsed ul{float:left;width:75%;margin-right:-2px}.ui-navbar-collapsed .ui-navbar-toggle{float:left;width:25%}.ui-navbar li.ui-navbar-truncate{position:absolute;left:-9999px;top:-9999px}.ui-navbar li .ui-btn,.ui-navbar .ui-navbar-toggle .ui-btn{display:block;font-size:12px;text-align:center;margin:0;border-right-width:0}.ui-navbar li .ui-btn{margin-right:-1px}.ui-navbar li .ui-btn:last-child{margin-right:0}.ui-header .ui-navbar li .ui-btn,.ui-header .ui-navbar .ui-navbar-toggle .ui-btn,.ui-footer .ui-navbar li .ui-btn,.ui-footer .ui-navbar .ui-navbar-toggle .ui-btn{border-top-width:0;border-bottom-width:0}.ui-navbar .ui-btn-inner{padding-left:2px;padding-right:2px}.ui-navbar-noicons li .ui-btn .ui-btn-inner,.ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner{padding-top:.8em;padding-bottom:.9em}.ui-navbar-expanded .ui-btn{margin:0;font-size:14px}.ui-navbar-expanded .ui-btn-inner{padding-left:5px;padding-right:5px}.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner{padding:45px 5px 15px;text-align:center}.ui-navbar-expanded .ui-btn-icon-top .ui-icon{top:15px}.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner{padding:15px 5px 45px;text-align:center}.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon{bottom:15px}.ui-navbar-expanded li .ui-btn .ui-btn-inner{min-height:2.5em}.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner{padding-top:1.8em;padding-bottom:1.9em}.ui-btn{display:block;text-align:center;cursor:pointer;position:relative;margin:.5em 5px;padding:0}.ui-btn:focus,.ui-btn:active{outline:0}.ui-header .ui-btn,.ui-footer .ui-btn,.ui-bar .ui-btn{display:inline-block;font-size:13px;margin:0}.ui-btn-inline{display:inline-block}.ui-btn-inner{padding:.6em 25px;display:block;height:100%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;position:relative}.ui-header .ui-btn-inner,.ui-footer .ui-btn-inner,.ui-bar .ui-btn-inner{padding:.4em 8px .5em}.ui-btn-icon-notext{display:inline-block;width:20px;height:20px;padding:2px 1px 2px 3px;text-indent:-9999px}.ui-btn-icon-notext .ui-btn-inner{padding:0}.ui-btn-icon-notext .ui-btn-text{position:absolute;left:-999px}.ui-btn-icon-left .ui-btn-inner{padding-left:33px}.ui-header .ui-btn-icon-left .ui-btn-inner,.ui-footer .ui-btn-icon-left .ui-btn-inner,.ui-bar .ui-btn-icon-left .ui-btn-inner{padding-left:27px}.ui-btn-icon-right .ui-btn-inner{padding-right:33px}.ui-header .ui-btn-icon-right .ui-btn-inner,.ui-footer .ui-btn-icon-right .ui-btn-inner,.ui-bar .ui-btn-icon-right .ui-btn-inner{padding-right:27px}.ui-btn-icon-top .ui-btn-inner{padding-top:33px}.ui-header .ui-btn-icon-top .ui-btn-inner,.ui-footer .ui-btn-icon-top .ui-btn-inner,.ui-bar .ui-btn-icon-top .ui-btn-inner{padding-top:27px}.ui-btn-icon-bottom .ui-btn-inner{padding-bottom:33px}.ui-header .ui-btn-icon-bottom .ui-btn-inner,.ui-footer .ui-btn-icon-bottom .ui-btn-inner,.ui-bar .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:27px}.ui-btn-icon-notext .ui-icon{display:block}.ui-btn-icon-left .ui-icon,.ui-btn-icon-right .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-btn-icon-top .ui-icon,.ui-btn-icon-bottom .ui-icon{position:absolute;left:50%;margin-left:-9px}.ui-btn-icon-left .ui-icon{left:10px}.ui-btn-icon-right .ui-icon{right:10px}.ui-header .ui-btn-icon-left .ui-icon,.ui-footer .ui-btn-icon-left .ui-icon,.ui-bar .ui-btn-icon-left .ui-icon{left:4px}.ui-header .ui-btn-icon-right .ui-icon,.ui-footer .ui-btn-icon-right .ui-icon,.ui-bar .ui-btn-icon-right .ui-icon{right:4px}.ui-header .ui-btn-icon-top .ui-icon,.ui-footer .ui-btn-icon-top .ui-icon,.ui-bar .ui-btn-icon-top .ui-icon{top:4px}.ui-header .ui-btn-icon-bottom .ui-icon,.ui-footer .ui-btn-icon-bottom .ui-icon,.ui-bar .ui-btn-icon-bottom .ui-icon{bottom:4px}.ui-btn-icon-top .ui-icon{top:5px}.ui-btn-icon-bottom .ui-icon{bottom:5px}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:button;opacity:0;cursor:pointer}.ui-collapsible-contain{margin:.5em 0}.ui-collapsible-heading{font-size:16px;display:block;margin:0 -8px;padding:0;border-width:0 0 1px 0;position:relative}.ui-collapsible-heading a{text-align:left;margin:0}.ui-collapsible-heading a .ui-btn-inner{padding-left:40px}.ui-collapsible-heading a span.ui-btn{position:absolute;left:6px;top:50%;margin:-12px 0 0 0;width:20px;height:20px;padding:1px 0 1px 2px;text-indent:-9999px}.ui-collapsible-heading a span.ui-btn .ui-btn-inner{padding:0}.ui-collapsible-heading a span.ui-btn .ui-icon{left:0;margin-top:-10px}.ui-collapsible-heading-status{position:absolute;left:-9999px}.ui-collapsible-content{display:block;padding:10px 0 10px 8px}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set{margin:.5em 0}.ui-collapsible-set .ui-collapsible-contain{margin:-1px 0 0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:.5em 0 1em}.ui-bar .ui-controlgroup{margin:0 .3em}.ui-controlgroup-label{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em}.ui-controlgroup-controls{display:block;width:95%}.ui-controlgroup li{list-style:none}.ui-controlgroup-vertical .ui-btn,.ui-controlgroup-vertical .ui-checkbox,.ui-controlgroup-vertical .ui-radio{margin:0;border-bottom-width:0}.ui-controlgroup-vertical .ui-controlgroup-last{border-bottom-width:1px}.ui-controlgroup-horizontal{padding:0}.ui-controlgroup-horizontal .ui-btn,.ui-controlgroup-horizontal .ui-checkbox,.ui-controlgroup-horizontal .ui-radio{margin:0 -5px 0 0;display:inline-block}.ui-controlgroup-horizontal .ui-checkbox .ui-btn,.ui-controlgroup-horizontal .ui-radio .ui-btn,.ui-controlgroup-horizontal .ui-checkbox:last-child,.ui-controlgroup-horizontal .ui-radio:last-child{margin-right:0}.ui-controlgroup-horizontal .ui-controlgroup-last{margin-right:0}.ui-controlgroup .ui-checkbox label,.ui-controlgroup .ui-radio label{font-size:16px}.min-width-480px .ui-controlgroup-label{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.min-width-480px .ui-controlgroup-controls{width:60%;display:inline-block}.ui-dialog{min-height:480px}.ui-dialog .ui-header,.ui-dialog .ui-content,.ui-dialog .ui-footer{margin:15px;position:relative}.ui-dialog .ui-header,.ui-dialog .ui-footer{z-index:10;width:auto}.ui-dialog .ui-content,.ui-dialog .ui-footer{margin-top:-15px}.ui-checkbox,.ui-radio{position:relative;margin:.2em 0 .5em;z-index:1}.ui-checkbox .ui-btn,.ui-radio .ui-btn{margin:0;text-align:left;z-index:2}.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner{padding-left:45px}.ui-checkbox .ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-checkbox .ui-btn-icon-left .ui-icon,.ui-radio .ui-btn-icon-left .ui-icon{left:15px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox input,.ui-radio input{position:absolute;left:20px;top:50%;width:10px;height:10px;margin:-5px 0 0 0;outline:0!important;z-index:1}.ui-field-contain{background:0;padding:1.5em 0;margin:0;border-bottom-width:1px;overflow:visible}.ui-field-contain:first-child{border-top-width:0}.min-width-480px .ui-field-contain{border-width:0;padding:0;margin:1em 0}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:button;left:0;top:0;width:100%;height:100%;opacity:.001}.ui-select .ui-btn select.ui-select-nativeonly{opacity:1}.ui-select .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-select .ui-btn-icon-right .ui-icon{right:15px}label.ui-select{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}.ui-select .ui-btn-text,.ui-selectmenu .ui-btn-text{display:inline-block;min-height:1em}.ui-select .ui-btn-text{text-overflow:ellipsis;overflow:hidden;width:85%}.ui-selectmenu{position:absolute;padding:0;z-index:100!important;width:80%;max-width:350px;padding:6px}.ui-selectmenu .ui-listview{margin:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-selectmenu-hidden{top:-9999px;left:-9999px}.ui-selectmenu-screen{position:absolute;top:0;left:0;width:100%;height:100%;z-index:99}.ui-screen-hidden,.ui-selectmenu-list .ui-li .ui-icon{display:none}.ui-selectmenu-list .ui-li .ui-icon{display:block}.ui-li.ui-selectmenu-placeholder{display:none}.min-width-480px label.ui-select{display:inline-block;width:20%;margin:0 2% 0 0}.min-width-480px .ui-select{width:60%;display:inline-block}.ui-selectmenu .ui-header h1:after{content:'.';visibility:hidden}label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}input.ui-input-text,textarea.ui-input-text{background-image:none;padding:.4em;line-height:1.4;font-size:16px;display:block;width:95%}input.ui-input-text{-webkit-appearance:none}textarea.ui-input-text{height:50px;-webkit-transition:height 200ms linear;-moz-transition:height 200ms linear;-o-transition:height 200ms linear;transition:height 200ms linear}.ui-input-search{padding:0 30px;width:77%;background-position:8px 50%;background-repeat:no-repeat;position:relative}.ui-input-search input.ui-input-text{border:0;width:98%;padding:.4em 0;margin:0;display:block;background:transparent none;outline:0!important}.ui-input-search .ui-input-clear{position:absolute;right:0;top:50%;margin-top:-14px}.ui-input-search .ui-input-clear-hidden{display:none}.min-width-480px label.ui-input-text{vertical-align:top}.min-width-480px label.ui-input-text{display:inline-block;width:20%;margin:0 2% 0 0}.min-width-480px input.ui-input-text,.min-width-480px textarea.ui-input-text,.min-width-480px .ui-input-search{width:60%;display:inline-block}.min-width-480px .ui-input-search{width:50%}.ui-listview{margin:0;counter-reset:listnumbering}.ui-content .ui-listview{margin:-15px}.ui-content .ui-listview-inset{margin:1em 0}.ui-listview,.ui-li{list-style:none;padding:0;zoom:1}.ui-li{display:block;margin:0;position:relative;overflow:hidden;text-align:left;border-width:0;border-top-width:1px}.ui-li .ui-btn-text{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-divider,.ui-li-static{padding:.5em 15px;font-size:14px;font-weight:bold;counter-reset:listnumbering}ol.ui-listview .ui-link-inherit:before,.ui-li-dec{font-size:.8em;display:inline-block;padding-right:.3em;font-weight:normal;counter-increment:listnumbering;content:counter(listnumbering) ". "}ol.ui-listview .ui-li-jsnumbering:before{content:""!important}.ui-listview-inset .ui-li{border-right-width:1px;border-left-width:1px}.ui-li:last-child{border-bottom-width:1px}.ui-li .ui-btn-inner{display:block;position:relative;padding:.7em 75px .7em 15px}.ui-li-has-thumb .ui-btn-inner{min-height:60px;padding-left:100px}.ui-li-has-icon .ui-btn-inner{min-height:20px;padding-left:40px}.ui-li-heading{font-size:16px;font-weight:bold;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-desc{font-size:12px;font-weight:normal;display:block;margin:-.5em 0 .6em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-thumb,.ui-li-icon{position:absolute;left:1px;top:0;max-height:80px;max-width:80px}.ui-li-icon{max-height:40px;max-width:40px;left:10px;top:.9em}.ui-li-thumb,.ui-li-icon,.ui-li-content{float:left;margin-right:10px}.ui-li-aside{float:right;width:50%;text-align:right;margin:.3em 0}.min-width-480px .ui-li-aside{width:45%}.ui-li-has-alt .ui-btn-inner{padding-right:95px}.ui-li-count{position:absolute;font-size:11px;font-weight:bold;padding:.2em .5em;top:50%;margin-top:-.9em;right:38px}.ui-li-divider .ui-li-count{right:10px}.ui-li-has-alt .ui-li-count{right:55px}.ui-li-link-alt{position:absolute;width:40px;height:100%;border-width:0;border-left-width:1px;top:0;right:0;margin:0;padding:0}.ui-li-link-alt .ui-btn{overflow:hidden;position:absolute;right:8px;top:50%;margin:-11px 0 0 0;border-bottom-width:1px}.ui-li-link-alt .ui-btn-inner{padding:0;position:static}.ui-li-link-alt .ui-btn .ui-icon{right:50%;margin-right:-9px}.ui-listview-filter{border-width:0;overflow:hidden;margin:-15px -15px 15px -15px}.ui-listview-filter .ui-input-search{margin:5px;width:auto;display:block}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}label.ui-slider{display:block}input.ui-slider-input,.min-width-480px input.ui-slider-input{display:inline-block;width:50px}select.ui-slider-switch{display:none}div.ui-slider{position:relative;display:inline-block;overflow:visible;height:15px;padding:0;margin:0 2% 0 20px;top:4px;width:66%}a.ui-slider-handle{position:absolute;z-index:10;top:50%;width:28px;height:28px;margin-top:-15px;margin-left:-15px}a.ui-slider-handle .ui-btn-inner{padding-left:0;padding-right:0}.min-width-480px label.ui-slider{display:inline-block;width:20%;margin:0 2% 0 0}.min-width-480px div.ui-slider{width:45%}div.ui-slider-switch{height:32px;overflow:hidden;margin-left:0}div.ui-slider-inneroffset{margin-left:50%;position:absolute;top:1px;height:100%;width:50%}div.ui-slider-handle-snapping{-webkit-transition:left 100ms linear}div.ui-slider-labelbg{position:absolute;top:0;margin:0;border-width:0}div.ui-slider-switch div.ui-slider-labelbg-a{width:60%;height:100%;left:0}div.ui-slider-switch div.ui-slider-labelbg-b{width:60%;height:100%;right:0}.ui-slider-switch-a div.ui-slider-labelbg-a,.ui-slider-switch-b div.ui-slider-labelbg-b{z-index:1}.ui-slider-switch-a div.ui-slider-labelbg-b,.ui-slider-switch-b div.ui-slider-labelbg-a{z-index:10}div.ui-slider-switch a.ui-slider-handle{z-index:20;width:101%;height:32px;margin-top:-18px;margin-left:-101%}span.ui-slider-label{width:100%;position:absolute;height:32px;font-size:16px;text-align:center;line-height:2;background:0;border-color:transparent}span.ui-slider-label-a{left:-100%;margin-right:-1px}span.ui-slider-label-b{right:-100%;margin-left:-1px} \ No newline at end of file diff --git a/openlp/plugins/remotes/html/jquery.mobile.js b/openlp/plugins/remotes/html/jquery.mobile.js new file mode 100644 index 000000000..44cc49e71 --- /dev/null +++ b/openlp/plugins/remotes/html/jquery.mobile.js @@ -0,0 +1,121 @@ +/*! + * jQuery Mobile v1.0a3 + * http://jquerymobile.com/ + * + * Copyright 2010, jQuery Project + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ +(function(a,d){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var g=0,e;(e=b[g])!=null;g++)a(e).triggerHandler("remove");c(b)}}else{var f=a.fn.remove;a.fn.remove=function(b,g){return this.each(function(){if(!g)if(!b||a.filter(b,[this]).length)a("*",this).add([this]).each(function(){a(this).triggerHandler("remove")});return f.call(a(this),b,g)})}}a.widget=function(b,g,e){var i=b.split(".")[0],h;b=b.split(".")[1];h=i+"-"+b;if(!e){e=g;g=a.Widget}a.expr[":"][h]=function(k){return!!a.data(k, +b)};a[i]=a[i]||{};a[i][b]=function(k,j){arguments.length&&this._createWidget(k,j)};g=new g;g.options=a.extend(true,{},g.options);a[i][b].prototype=a.extend(true,g,{namespace:i,widgetName:b,widgetEventPrefix:a[i][b].prototype.widgetEventPrefix||b,widgetBaseClass:h},e);a.widget.bridge(b,a[i][b])};a.widget.bridge=function(b,g){a.fn[b]=function(e){var i=typeof e==="string",h=Array.prototype.slice.call(arguments,1),k=this;e=!i&&h.length?a.extend.apply(null,[true,e].concat(h)):e;if(i&&e.charAt(0)==="_")return k; +i?this.each(function(){var j=a.data(this,b);if(!j)throw"cannot call methods on "+b+" prior to initialization; attempted to call method '"+e+"'";if(!a.isFunction(j[e]))throw"no such method '"+e+"' for "+b+" widget instance";var o=j[e].apply(j,h);if(o!==j&&o!==d){k=o;return false}}):this.each(function(){var j=a.data(this,b);j?j.option(e||{})._init():a.data(this,b,new g(e,this))});return k}};a.Widget=function(b,g){arguments.length&&this._createWidget(b,g)};a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"", +options:{disabled:false},_createWidget:function(b,g){a.data(g,this.widgetName,this);this.element=a(g);this.options=a.extend(true,{},this.options,this._getCreateOptions(),b);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){var b={};if(a.metadata)b=a.metadata.get(element)[this.widgetName];return b},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName); +this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(b,g){var e=b;if(arguments.length===0)return a.extend({},this.options);if(typeof b==="string"){if(g===d)return this.options[b];e={};e[b]=g}this._setOptions(e);return this},_setOptions:function(b){var g=this;a.each(b,function(e,i){g._setOption(e,i)});return this},_setOption:function(b,g){this.options[b]=g;if(b=== +"disabled")this.widget()[g?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",g);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(b,g,e){var i=this.options[b];g=a.Event(g);g.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase();e=e||{};if(g.originalEvent){b=a.event.props.length;for(var h;b;){h=a.event.props[--b];g[h]=g.originalEvent[h]}}this.element.trigger(g, +e);return!(a.isFunction(i)&&i.call(this.element[0],g,e)===false||g.isDefaultPrevented())}}})(jQuery);(function(a,d){a.widget("mobile.widget",{_getCreateOptions:function(){var c=this.element,f={};a.each(this.options,function(b){var g=c.data(b.replace(/[A-Z]/g,function(e){return"-"+e.toLowerCase()}));if(g!==d)f[b]=g});return f}})})(jQuery); +(function(a){function d(){var g=c.width(),e=[],i=[],h;f.removeClass("min-width-"+b.join("px min-width-")+"px max-width-"+b.join("px max-width-")+"px");a.each(b,function(k,j){g>=j&&e.push("min-width-"+j+"px");g<=j&&i.push("max-width-"+j+"px")});if(e.length)h=e.join(" ");if(i.length)h+=" "+i.join(" ");f.addClass(h)}var c=a(window),f=a("html"),b=[320,480,768,1024];a.mobile.media=function(){var g={},e=a("
"),i=a("").append(e);return function(h){if(!(h in g)){var k=document.createElement("style"), +j="@media "+h+" { #jquery-mediatest { position:absolute; } }";k.type="text/css";if(k.styleSheet)k.styleSheet.cssText=j;else k.appendChild(document.createTextNode(j));f.prepend(i).prepend(k);g[h]=e.css("position")==="absolute";i.add(k).remove()}return g[h]}}();a.mobile.addResolutionBreakpoints=function(g){if(a.type(g)==="array")b=b.concat(g);else b.push(g);b.sort(function(e,i){return e-i});d()};a(document).bind("mobileinit.htmlclass",function(){c.bind("orientationchange.htmlclass resize.htmlclass", +function(g){g.orientation&&f.removeClass("portrait landscape").addClass(g.orientation);d()})});a(function(){c.trigger("orientationchange.htmlclass")})})(jQuery); +(function(a,d){function c(h){var k=h.charAt(0).toUpperCase()+h.substr(1);h=(h+" "+g.join(k+" ")+k).split(" ");for(var j in h)if(b[j]!==d)return true}var f=a("").prependTo("html"),b=f[0].style,g=["webkit","moz","o"],e=window.palmGetResource||window.PalmServiceBridge,i=window.blackberry;a.extend(a.support,{orientation:"orientation"in window,touch:"ontouchend"in document,cssTransitions:"WebKitTransitionEvent"in window,pushState:!!history.pushState,mediaquery:a.mobile.media("only all"),cssPseudoElement:!!c("content"), +boxShadow:!!c("boxShadow")&&!i,scrollTop:("pageXOffset"in window||"scrollTop"in document.documentElement||"scrollTop"in f[0])&&!e,dynamicBaseTag:function(){var h=location.protocol+"//"+location.host+location.pathname+"ui-dir/",k=a("head base"),j=null,o="";if(k.length)o=k.attr("href");else k=j=a("",{href:h}).appendTo("head");var p=a("").prependTo(f)[0].href;k[0].href=o?o:location.pathname;j&&j.remove();return p.indexOf(h)===0}()});f.remove();a.support.boxShadow||a("html").addClass("ui-mobile-nosupport-boxshadow")})(jQuery); +(function(a,d){a.each("touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(e,i){a.fn[i]=function(h){return h?this.bind(i,h):this.trigger(i)};a.attrFn[i]=true});var c=a.support.touch,f=c?"touchstart":"mousedown",b=c?"touchend":"mouseup",g=c?"touchmove":"mousemove";a.event.special.scrollstart={enabled:true,setup:function(){function e(j,o){h=o;var p=j.type;j.type=h?"scrollstart":"scrollstop";a.event.handle.call(i,j);j.type= +p}var i=this,h,k;a(i).bind("touchmove scroll",function(j){if(a.event.special.scrollstart.enabled){h||e(j,true);clearTimeout(k);k=setTimeout(function(){e(j,false)},50)}})}};a.event.special.tap={setup:function(){var e=this,i=a(e);i.bind("mousedown touchstart",function(h){function k(n){if(n.type=="scroll")j=true;else{n=n.type=="touchmove"?n.originalEvent.touches[0]:n;if(Math.abs(v[0]-n.pageX)>10||Math.abs(v[1]-n.pageY)>10)j=true}}if(h.which&&h.which!==1||i.data("prevEvent")&&i.data("prevEvent")!==h.type)return false; +i.data("prevEvent",h.type);setTimeout(function(){i.removeData("prevEvent")},800);var j=false,o=true,p=h.target,t=h.originalEvent,v=h.type=="touchstart"?[t.touches[0].pageX,t.touches[0].pageY]:[h.pageX,h.pageY],m,r;r=setTimeout(function(){if(o&&!j){m=h.type;h.type="taphold";a.event.handle.call(e,h);h.type=m}},750);a(window).one("scroll",k);i.bind("mousemove touchmove",k).one("mouseup touchend",function(n){i.unbind("mousemove touchmove",k);a(window).unbind("scroll",k);clearTimeout(r);o=false;if(!j&& +p==n.target){m=n.type;n.type="tap";a.event.handle.call(e,n);n.type=m}})})}};a.event.special.swipe={setup:function(){var e=a(this);e.bind(f,function(i){function h(p){if(j){var t=p.originalEvent.touches?p.originalEvent.touches[0]:p;o={time:(new Date).getTime(),coords:[t.pageX,t.pageY]};Math.abs(j.coords[0]-o.coords[0])>10&&p.preventDefault()}}var k=i.originalEvent.touches?i.originalEvent.touches[0]:i,j={time:(new Date).getTime(),coords:[k.pageX,k.pageY],origin:a(i.target)},o;e.bind(g,h).one(b,function(){e.unbind(g, +h);if(j&&o)if(o.time-j.time<1E3&&Math.abs(j.coords[0]-o.coords[0])>30&&Math.abs(j.coords[1]-o.coords[1])<75)j.origin.trigger("swipe").trigger(j.coords[0]>o.coords[0]?"swipeleft":"swiperight");j=o=d})})}};(function(e){function i(){var o=k();if(o!==j){j=o;h.trigger("orientationchange")}}var h=e(window),k,j;e.event.special.orientationchange={setup:function(){if(e.support.orientation)return false;j=k();h.bind("resize",i)},teardown:function(){if(e.support.orientation)return false;h.unbind("resize",i)}, +add:function(o){var p=o.handler;o.handler=function(t){t.orientation=k();return p.apply(this,arguments)}}};k=function(){var o=document.documentElement;return o&&o.clientWidth/o.clientHeight<1.1?"portrait":"landscape"}})(jQuery);a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(e,i){a.event.special[e]={setup:function(){a(this).bind(i,a.noop)}}})})(jQuery); +(function(a,d,c){function f(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}var b="hashchange",g=document,e,i=a.event.special,h=g.documentMode,k="on"+b in d&&(h===c||h>7);a.fn[b]=function(j){return j?this.bind(b,j):this.trigger(b)};a.fn[b].delay=50;i[b]=a.extend(i[b],{setup:function(){if(k)return false;a(e.start)},teardown:function(){if(k)return false;a(e.stop)}});e=function(){function j(){var n=f(),u=r(t);if(n!==t){m(t=n,u);a(d).trigger(b)}else if(u!==t)location.href=location.href.replace(/#.*/, +"")+u;p=setTimeout(j,a.fn[b].delay)}var o={},p,t=f(),v=function(n){return n},m=v,r=v;o.start=function(){p||j()};o.stop=function(){p&&clearTimeout(p);p=c};a.browser.msie&&!k&&function(){var n,u;o.start=function(){if(!n){u=(u=a.fn[b].src)&&u+f();n=a('