forked from openlp/openlp
More docstrings cleanups.
This commit is contained in:
parent
e66fa9b87d
commit
b3af02308b
@ -31,42 +31,58 @@ class Plugin(object):
|
||||
Base class for openlp plugins to inherit from.
|
||||
|
||||
Basic attributes are:
|
||||
* name
|
||||
|
||||
``name``
|
||||
The name that should appear in the plugins list.
|
||||
* version
|
||||
|
||||
``version``
|
||||
The version number of this iteration of the plugin.
|
||||
* icon
|
||||
|
||||
``icon``
|
||||
An instance of QIcon, which holds an icon for this plugin.
|
||||
* config
|
||||
|
||||
``config``
|
||||
An instance of PluginConfig, which allows plugins to read and write to
|
||||
openlp.org's configuration. This is pre-instantiated.
|
||||
* log
|
||||
|
||||
``log``
|
||||
A log object used to log debugging messages. This is pre-instantiated.
|
||||
|
||||
Hook functions:
|
||||
* check_pre_conditions()
|
||||
|
||||
``check_pre_conditions()``
|
||||
Provides the Plugin with a handle to check if it can be loaded.
|
||||
* get_media_manager_item()
|
||||
|
||||
``get_media_manager_item()``
|
||||
Returns an instance of MediaManagerItem to be used in the Media Manager.
|
||||
* add_import_menu_item(import_menu)
|
||||
|
||||
``add_import_menu_item(import_menu)``
|
||||
Add an item to the Import menu.
|
||||
* add_export_menu_item(export_menu)
|
||||
|
||||
``add_export_menu_item(export_menu)``
|
||||
Add an item to the Export menu.
|
||||
* get_settings_tab()
|
||||
|
||||
``get_settings_tab()``
|
||||
Returns an instance of SettingsTabItem to be used in the Settings dialog.
|
||||
* add_to_menu(menubar)
|
||||
|
||||
``add_to_menu(menubar)``
|
||||
A method to add a menu item to anywhere in the menu, given the menu bar.
|
||||
* handle_event(event)
|
||||
|
||||
``handle_event(event)``
|
||||
A method use to handle events, given an Event object.
|
||||
* about()
|
||||
|
||||
``about()``
|
||||
Used in the plugin manager, when a person clicks on the 'About' button.
|
||||
* save(data)
|
||||
|
||||
``save(data)``
|
||||
A method to convert the plugin's data to a string to be stored in the
|
||||
Service file.
|
||||
* load(string)
|
||||
|
||||
``load(string)``
|
||||
A method to convert the string from a Service file into the plugin's
|
||||
own data format.
|
||||
* render(theme, screen_number)
|
||||
|
||||
``render(theme, screen_number)``
|
||||
A method used to render something to the screen, given the current theme
|
||||
and screen number.
|
||||
"""
|
||||
@ -78,11 +94,20 @@ class Plugin(object):
|
||||
"""
|
||||
This is the constructor for the plugin object. This provides an easy
|
||||
way for descendent plugins to populate common data. This method *must*
|
||||
be overridden, like so:
|
||||
class MyPlugin(Plugin):
|
||||
def __init__(self):
|
||||
Plugin.__init(self, 'MyPlugin', '0.1')
|
||||
...
|
||||
be overridden, like so::
|
||||
|
||||
class MyPlugin(Plugin):
|
||||
def __init__(self):
|
||||
Plugin.__init(self, u'MyPlugin', u'0.1')
|
||||
|
||||
``name``
|
||||
Defaults to *None*. The name of the plugin.
|
||||
|
||||
``version``
|
||||
Defaults to *None*. The version of the plugin.
|
||||
|
||||
``plugin_helpers``
|
||||
Defaults to *None*. A list of helper objects.
|
||||
"""
|
||||
if name is not None:
|
||||
self.name = name
|
||||
@ -107,50 +132,59 @@ class Plugin(object):
|
||||
def check_pre_conditions(self):
|
||||
"""
|
||||
Provides the Plugin with a handle to check if it can be loaded.
|
||||
|
||||
Returns True or False.
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_media_manager_item(self):
|
||||
"""
|
||||
Construct a MediaManagerItem object with all the buttons and things you
|
||||
need, and return it for integration into openlp.org.
|
||||
Construct a MediaManagerItem object with all the buttons and things
|
||||
you need, and return it for integration into openlp.org.
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_import_menu_item(self, import_menu):
|
||||
"""
|
||||
Create a menu item and add it to the "Import" menu.
|
||||
|
||||
``import_menu``
|
||||
The Import menu.
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_export_menu_item(self, export_menu):
|
||||
"""
|
||||
Create a menu item and add it to the "Export" menu.
|
||||
|
||||
``export_menu``
|
||||
The Export menu
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_settings_tab(self):
|
||||
"""
|
||||
Create a menu item and add it to the "Import" menu.
|
||||
Create a tab for the settings window.
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_to_menu(self, menubar):
|
||||
"""
|
||||
Add menu items to the menu, given the menubar.
|
||||
|
||||
``menubar``
|
||||
The application's menu bar.
|
||||
"""
|
||||
pass
|
||||
|
||||
def handle_event(self, event):
|
||||
"""
|
||||
Handle the event contained in the event object.
|
||||
"""
|
||||
def handle_event(self, event):
|
||||
"""
|
||||
Handle the event contained in the event object. If you want
|
||||
to use this default behaviour, you must set self.dnd_id equal
|
||||
to that sent by the dnd source - eg the MediaItem
|
||||
|
||||
``event``
|
||||
An object describing the event.
|
||||
"""
|
||||
# default behaviour - can be overridden if desired
|
||||
log.debug(u'Handle event called with event %s with payload %s'%(event.event_type, event.payload))
|
||||
@ -175,6 +209,9 @@ class Plugin(object):
|
||||
"""
|
||||
Service item data is passed to this function, which should return a
|
||||
string which can be written to the service file.
|
||||
|
||||
``data``
|
||||
The data to be saved.
|
||||
"""
|
||||
pass
|
||||
|
||||
@ -182,12 +219,21 @@ class Plugin(object):
|
||||
"""
|
||||
A string from the service file is passed in. This function parses and
|
||||
sets up the internals of the plugin.
|
||||
|
||||
``string``
|
||||
The data to be loaded into the plugin.
|
||||
"""
|
||||
pass
|
||||
|
||||
def render(self, theme, screen=None):
|
||||
"""
|
||||
Render the screenth screenful of data using theme settings in theme.
|
||||
|
||||
``theme``
|
||||
The theme to use when rendering.
|
||||
|
||||
``screen``
|
||||
Defaults to *None*. The screen to render to.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
@ -29,28 +29,50 @@ class PluginConfig(object):
|
||||
"""
|
||||
Initialise the plugin config object, setting the section name to the
|
||||
plugin name.
|
||||
|
||||
``plugin_name``
|
||||
The name of the plugin to use as a section name.
|
||||
"""
|
||||
self.section = plugin_name.lower()
|
||||
|
||||
def get_config(self, key, default=None):
|
||||
"""
|
||||
Get a configuration value from the configuration registry.
|
||||
|
||||
``key``
|
||||
The name of configuration to load.
|
||||
|
||||
``default``
|
||||
Defaults to *None*. The default value to return if there is no
|
||||
other value.
|
||||
"""
|
||||
return ConfigHelper.get_config(self.section, key, default)
|
||||
|
||||
def delete_config(self, key):
|
||||
"""
|
||||
Delete a configuration value from the configuration registry.
|
||||
|
||||
``key``
|
||||
The name of the configuration to remove.
|
||||
"""
|
||||
return ConfigHelper.delete_config(self.section, key)
|
||||
|
||||
def set_config(self, key, value):
|
||||
"""
|
||||
Set a configuration value in the configuration registry.
|
||||
|
||||
``key``
|
||||
The name of the configuration to save.
|
||||
|
||||
``value``
|
||||
The value of the configuration to save.
|
||||
"""
|
||||
return ConfigHelper.set_config(self.section, key, value)
|
||||
|
||||
def get_data_path(self):
|
||||
"""
|
||||
Dynamically build the data file path for a plugin.
|
||||
"""
|
||||
#app_data = ConfigHelper.get_data_path()
|
||||
app_data = ConfigHelper.get_data_path()
|
||||
safe_name = self.section.replace(u' ',u'-')
|
||||
@ -61,9 +83,21 @@ class PluginConfig(object):
|
||||
return path
|
||||
|
||||
def set_data_path(self, path):
|
||||
"""
|
||||
Set the data file path.
|
||||
|
||||
``path``
|
||||
The path to save.
|
||||
"""
|
||||
return self.set_config(u'data path', os.path.basename(path))
|
||||
|
||||
def get_files(self, suffix=None):
|
||||
"""
|
||||
Get a list of files from the data files path.
|
||||
|
||||
``suffix``
|
||||
Defaults to *None*. The extension to search for.
|
||||
"""
|
||||
try:
|
||||
files = os.listdir(self.get_data_path())
|
||||
except:
|
||||
@ -86,7 +120,10 @@ class PluginConfig(object):
|
||||
|
||||
def load_list(self, name):
|
||||
"""
|
||||
Load a list from the config file
|
||||
Load a list from the config file.
|
||||
|
||||
``name``
|
||||
The name of the list.
|
||||
"""
|
||||
list_count = self.get_config(u'%s count' % name)
|
||||
if list_count is not None:
|
||||
@ -102,7 +139,13 @@ class PluginConfig(object):
|
||||
|
||||
def set_list(self, name, list):
|
||||
"""
|
||||
Save a list to the config file
|
||||
Save a list to the config file.
|
||||
|
||||
``name``
|
||||
The name of the list to save.
|
||||
|
||||
``list``
|
||||
The list of values to save.
|
||||
"""
|
||||
old_count = int(self.get_config(u'%s count' % name, int(0)))
|
||||
new_count = len(list)
|
||||
@ -116,7 +159,10 @@ class PluginConfig(object):
|
||||
|
||||
def get_last_dir(self, num=None):
|
||||
"""
|
||||
Read the last directory used for plugin
|
||||
Read the last directory used for plugin.
|
||||
|
||||
``num``
|
||||
Defaults to *None*. A further qualifier.
|
||||
"""
|
||||
if num is not None:
|
||||
name = u'last directory %d' % num
|
||||
@ -129,7 +175,10 @@ class PluginConfig(object):
|
||||
|
||||
def set_last_dir(self, directory, num=None):
|
||||
"""
|
||||
Save the last directory used for plugin
|
||||
Save the last directory used for plugin.
|
||||
|
||||
``num``
|
||||
Defaults to *None*. A further qualifier.
|
||||
"""
|
||||
if num is not None:
|
||||
name = u'last directory %d' % num
|
||||
|
@ -34,8 +34,11 @@ class PluginManager(object):
|
||||
|
||||
def __init__(self, dir):
|
||||
"""
|
||||
The constructor for the plugin manager.
|
||||
Passes the controllers on to the plugins for them to interact with via their ServiceItems
|
||||
The constructor for the plugin manager. Passes the controllers on to
|
||||
the plugins for them to interact with via their ServiceItems.
|
||||
|
||||
``dir``
|
||||
The directory to search for plugins.
|
||||
"""
|
||||
log.info(u'Plugin manager initing')
|
||||
if not dir in sys.path:
|
||||
@ -49,7 +52,16 @@ class PluginManager(object):
|
||||
|
||||
def find_plugins(self, dir, plugin_helpers, eventmanager):
|
||||
"""
|
||||
Scan the directory dir for objects inheriting from openlp.plugin
|
||||
Scan the directory dir for objects inheriting from ``openlp.plugin``.
|
||||
|
||||
``dir``
|
||||
The directory to scan.
|
||||
|
||||
``plugin_helpers``
|
||||
A list of helper objects to pass to the plugins.
|
||||
|
||||
``eventmanager``
|
||||
The event manager to pass to the plugins.
|
||||
"""
|
||||
self.plugin_helpers = plugin_helpers
|
||||
startdepth = len(os.path.abspath(dir).split(os.sep))
|
||||
@ -104,8 +116,8 @@ class PluginManager(object):
|
||||
|
||||
def hook_media_manager(self, mediatoolbox):
|
||||
"""
|
||||
Loop through all the plugins. If a plugin has a valid media manager item,
|
||||
add it to the media manager.
|
||||
Loop through all the plugins. If a plugin has a valid media manager
|
||||
item, add it to the media manager.
|
||||
|
||||
``mediatoolbox``
|
||||
The Media Manager itself.
|
||||
@ -118,8 +130,11 @@ class PluginManager(object):
|
||||
|
||||
def hook_settings_tabs(self, settingsform=None):
|
||||
"""
|
||||
Loop through all the plugins. If a plugin has a valid settings tab item,
|
||||
add it to the settings tab.
|
||||
Loop through all the plugins. If a plugin has a valid settings tab
|
||||
item, add it to the settings tab.
|
||||
|
||||
``settingsform``
|
||||
Defaults to *None*. The settings form to add tabs to.
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
settings_tab = plugin.get_settings_tab()
|
||||
@ -131,24 +146,30 @@ class PluginManager(object):
|
||||
|
||||
def hook_import_menu(self, import_menu):
|
||||
"""
|
||||
Loop through all the plugins and give them an opportunity to add an item
|
||||
to the import menu.
|
||||
Loop through all the plugins and give them an opportunity to add an
|
||||
item to the import menu.
|
||||
|
||||
``import_menu``
|
||||
The Import menu.
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
plugin.add_import_menu_item(import_menu)
|
||||
|
||||
def hook_export_menu(self, export_menu):
|
||||
"""
|
||||
Loop through all the plugins and give them an opportunity to add an item
|
||||
to the export menu.
|
||||
Loop through all the plugins and give them an opportunity to add an
|
||||
item to the export menu.
|
||||
|
||||
``export_menu``
|
||||
The Export menu.
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
plugin.add_export_menu_item(export_menu)
|
||||
|
||||
def initialise_plugins(self):
|
||||
"""
|
||||
Loop through all the plugins and give them an opportunity to add an item
|
||||
to the export menu.
|
||||
Loop through all the plugins and give them an opportunity to
|
||||
initialise themselves.
|
||||
"""
|
||||
for plugin in self.plugins:
|
||||
plugin.initialise()
|
||||
|
@ -18,12 +18,12 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
import logging
|
||||
import os, os.path
|
||||
import os
|
||||
import sys
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
class Renderer:
|
||||
class Renderer(object):
|
||||
"""
|
||||
Genarates a pixmap image of a array of text. The Text is formatted to
|
||||
make sure it fits on the screen and if not extra frames a generated.
|
||||
@ -33,6 +33,9 @@ class Renderer:
|
||||
log.info(u'Renderer Loaded')
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialise the renderer.
|
||||
"""
|
||||
self._rect = None
|
||||
self._debug = 0
|
||||
self._right_margin = 64 # the amount of right indent
|
||||
@ -47,11 +50,20 @@ class Renderer:
|
||||
self._bg_frame_small = None
|
||||
|
||||
def set_debug(self, debug):
|
||||
"""
|
||||
Set the debug mode of the renderer.
|
||||
|
||||
``debug``
|
||||
The debug mode.
|
||||
"""
|
||||
self._debug=debug
|
||||
|
||||
def set_theme(self, theme):
|
||||
"""
|
||||
External API to pass in the theme to be used
|
||||
Set the theme to be used.
|
||||
|
||||
``theme``
|
||||
The theme to be used.
|
||||
"""
|
||||
log.debug(u'set theme')
|
||||
self._theme = theme
|
||||
@ -64,12 +76,21 @@ class Renderer:
|
||||
self.set_bg_image(theme.background_filename)
|
||||
|
||||
def set_bg_image(self, filename):
|
||||
"""
|
||||
Set a background image.
|
||||
|
||||
``filename``
|
||||
The name of the image file.
|
||||
"""
|
||||
log.debug(u'set bg image %s', filename)
|
||||
self._bg_image_filename = unicode(filename)
|
||||
if self._frame is not None:
|
||||
self.scale_bg_image()
|
||||
|
||||
def scale_bg_image(self):
|
||||
"""
|
||||
Scale the background image to fit the screen.
|
||||
"""
|
||||
assert self._frame
|
||||
preview = QtGui.QImage(self._bg_image_filename)
|
||||
width = self._frame.width()
|
||||
@ -89,7 +110,16 @@ class Renderer:
|
||||
|
||||
def set_frame_dest(self, frame_width, frame_height, preview=False):
|
||||
"""
|
||||
External API to pass the frame size to be painted
|
||||
Set the size of the slide.
|
||||
|
||||
``frame_width``
|
||||
The width of the slide.
|
||||
|
||||
``frame_height``
|
||||
The height of the slide.
|
||||
|
||||
``preview``
|
||||
Defaults to *False*. Whether or not to generate a preview.
|
||||
"""
|
||||
if preview == True:
|
||||
self._bg_frame = None
|
||||
@ -103,7 +133,14 @@ class Renderer:
|
||||
|
||||
def format_slide(self, words, footer):
|
||||
"""
|
||||
External API to sort out the text to pe placed on the frame
|
||||
Figure out how much text can appear on a slide, using the current
|
||||
theme settings.
|
||||
|
||||
``words``
|
||||
The words to be fitted on the slide.
|
||||
|
||||
``footer``
|
||||
The footer of the slide.
|
||||
"""
|
||||
log.debug(u'format_slide - Start')
|
||||
verses = []
|
||||
@ -120,15 +157,28 @@ class Renderer:
|
||||
|
||||
def set_text_rectangle(self, rect_main, rect_footer):
|
||||
"""
|
||||
Sets the rectangle within which text should be rendered
|
||||
Sets the rectangle within which text should be rendered.
|
||||
|
||||
``rect_main``
|
||||
The main text block.
|
||||
|
||||
``rect_footer``
|
||||
The footer text block.
|
||||
"""
|
||||
self._rect = rect_main
|
||||
self._rect_footer = rect_footer
|
||||
|
||||
def generate_frame_from_lines(self, lines, footer_lines=None):
|
||||
"""
|
||||
Render a set of lines according to the theme, return bounding box
|
||||
"""
|
||||
Render a set of lines according to the theme, and return the block
|
||||
dimensions.
|
||||
|
||||
``lines``
|
||||
The lines to be rendered.
|
||||
|
||||
``footer_lines``
|
||||
Defaults to *None*. The footer to render.
|
||||
"""
|
||||
log.debug(u'generate_frame_from_lines - Start')
|
||||
#print "Render Lines ", lines
|
||||
bbox = self._render_lines_unaligned(lines, False)
|
||||
@ -139,14 +189,15 @@ class Renderer:
|
||||
x, y = self._correctAlignment(self._rect, bbox)
|
||||
bbox = self._render_lines_unaligned(lines, False, (x, y), True)
|
||||
if footer_lines is not None:
|
||||
bbox = self._render_lines_unaligned(footer_lines, True, (self._rect_footer.left(), self._rect_footer.top()), True )
|
||||
bbox = self._render_lines_unaligned(footer_lines, True,
|
||||
(self._rect_footer.left(), self._rect_footer.top()), True)
|
||||
log.debug(u'generate_frame_from_lines - Finish')
|
||||
return self._frame
|
||||
|
||||
def _generate_background_frame(self):
|
||||
"""
|
||||
Generate a background frame to the same size as the frame to be used
|
||||
Results cached for performance reasons.
|
||||
Generate a background frame to the same size as the frame to be used.
|
||||
Results are cached for performance reasons.
|
||||
"""
|
||||
assert(self._theme)
|
||||
self._bg_frame = QtGui.QImage(self._frame.width(), self._frame.height(),
|
||||
@ -196,11 +247,19 @@ class Renderer:
|
||||
|
||||
def _split_set_of_lines(self, lines, footer):
|
||||
"""
|
||||
Given a list of lines, decide how to split them best if they don't all fit on the screen
|
||||
- this is done by splitting at 1/2, 1/3 or 1/4 of the set
|
||||
If it doesn't fit, even at this size, just split at each opportunity.
|
||||
We'll do this by getting the bounding box of each line, and then summing them appropriately
|
||||
Returns a list of [lists of lines], one set for each screenful
|
||||
Given a list of lines, decide how to split them best if they don't all
|
||||
fit on the screen. This is done by splitting at 1/2, 1/3 or 1/4 of the
|
||||
set. If it doesn't fit, even at this size, just split at each
|
||||
opportunity. We'll do this by getting the bounding box of each line,
|
||||
and then summing them appropriately.
|
||||
|
||||
Returns a list of [lists of lines], one set for each screenful.
|
||||
|
||||
``lines``
|
||||
The lines of text to split.
|
||||
|
||||
``footer``
|
||||
The footer text.
|
||||
"""
|
||||
bboxes = []
|
||||
for line in lines:
|
||||
@ -254,6 +313,15 @@ class Renderer:
|
||||
return retval
|
||||
|
||||
def _correctAlignment(self, rect, bbox):
|
||||
"""
|
||||
Corrects the vertical alignment of text.
|
||||
|
||||
``rect``
|
||||
The block dimentions.
|
||||
|
||||
``bbox``
|
||||
Footer dimensions?
|
||||
"""
|
||||
x = rect.left()
|
||||
if int(self._theme.display_verticalAlign) == 0:
|
||||
# top align
|
||||
@ -268,13 +336,26 @@ class Renderer:
|
||||
log.error(u'Invalid value for theme.VerticalAlign:%s' % self._theme.display_verticalAlign)
|
||||
return x, y
|
||||
|
||||
def _render_lines_unaligned(self, lines, footer, tlcorner=(0,0), live=False):
|
||||
def _render_lines_unaligned(self, lines, footer, tlcorner=(0, 0), live=False):
|
||||
"""
|
||||
Given a list of lines to render, render each one in turn
|
||||
(using the _render_single_line fn - which may result in going
|
||||
off the bottom) They are expected to be pre-arranged to less
|
||||
than a screenful (eg. by using split_set_of_lines)
|
||||
Returns the bounding box of the text as QRect
|
||||
Given a list of lines to render, render each one in turn (using the
|
||||
``_render_single_line`` fn - which may result in going off the bottom).
|
||||
They are expected to be pre-arranged to less than a screenful (eg. by
|
||||
using split_set_of_lines).
|
||||
|
||||
Returns the bounding box of the text as QRect.
|
||||
|
||||
``lines``
|
||||
The lines of text to render.
|
||||
|
||||
``footer``
|
||||
The slide footer.
|
||||
|
||||
``tlcorner``
|
||||
Defaults to *``(0, 0)``*. Co-ordinates of the top left corner.
|
||||
|
||||
``live``
|
||||
Defaults to *False*. Whether or not this is a live screen.
|
||||
"""
|
||||
x, y = tlcorner
|
||||
brx = x
|
||||
@ -282,25 +363,37 @@ class Renderer:
|
||||
for line in lines:
|
||||
# render after current bottom, but at original left edge
|
||||
# keep track of right edge to see which is biggest
|
||||
(thisx, bry) = self._render_and_wrap_single_line(line, footer, (x , bry), live)
|
||||
(thisx, bry) = self._render_and_wrap_single_line(line, footer, (x, bry), live)
|
||||
if (thisx > brx):
|
||||
brx = thisx
|
||||
retval = QtCore.QRect(x, y,brx-x, bry-y)
|
||||
retval = QtCore.QRect(x, y, brx - x, bry - y)
|
||||
if self._debug:
|
||||
painter = QtGui.QPainter()
|
||||
painter.begin(self._frame)
|
||||
painter.setPen(QtGui.QPen(QtGui.QColor(0,0,255)))
|
||||
painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 255)))
|
||||
painter.drawRect(retval)
|
||||
painter.end()
|
||||
return retval
|
||||
return retval
|
||||
|
||||
def _render_and_wrap_single_line(self, line, footer, tlcorner=(0,0), live=False):
|
||||
def _render_and_wrap_single_line(self, line, footer, tlcorner=(0, 0), live=False):
|
||||
"""
|
||||
Render a single line of words onto the DC, top left corner
|
||||
specified.
|
||||
If the line is too wide for the context, it wraps, but
|
||||
right-aligns the surplus words in the manner of song lyrics
|
||||
Render a single line of words onto the DC, top left corner specified.
|
||||
If the line is too wide for the context, it wraps, but right-aligns
|
||||
the surplus words in the manner of song lyrics.
|
||||
|
||||
Returns the bottom-right corner (of what was rendered) as a tuple(x, y).
|
||||
|
||||
``line``
|
||||
Line of text to be rendered.
|
||||
|
||||
``footer``
|
||||
The footer of the slide.
|
||||
|
||||
``tlcorner``
|
||||
Defaults to *``(0, 0)``*. The top left corner.
|
||||
|
||||
``live``
|
||||
Defaults to *False*. Whether or not this is a live screen.
|
||||
"""
|
||||
x, y = tlcorner
|
||||
# We draw the text to see how big it is and then iterate to make it fit
|
||||
@ -397,6 +490,9 @@ class Renderer:
|
||||
return brcorner
|
||||
|
||||
def _set_theme_font(self):
|
||||
"""
|
||||
Set the fonts from the current theme settings.
|
||||
"""
|
||||
self.footerFont = QtGui.QFont(self._theme.font_footer_name,
|
||||
int(self._theme.font_footer_proportion), # size
|
||||
QtGui.QFont.Normal, # weight
|
||||
@ -408,11 +504,26 @@ class Renderer:
|
||||
0)# italic
|
||||
self.mainFont.setPixelSize(int(self._theme.font_main_proportion))
|
||||
|
||||
def _get_extent_and_render(self, line, footer, tlcorner=(0,0), draw=False, color=None):
|
||||
def _get_extent_and_render(self, line, footer, tlcorner=(0, 0), draw=False, color=None):
|
||||
"""
|
||||
Find bounding box of text - as render_single_line.
|
||||
If draw is set, actually draw the text to the current DC as well
|
||||
return width and height of text as a tuple (w,h)
|
||||
Find bounding box of text - as render_single_line. If draw is set,
|
||||
actually draw the text to the current DC as well return width and
|
||||
height of text as a tuple (w, h).
|
||||
|
||||
``line``
|
||||
The line of text to render.
|
||||
|
||||
``footer``
|
||||
The footer text.
|
||||
|
||||
``tlcorner``
|
||||
Defaults to *``(0, 0)``*. The top left corner co-ordinates.
|
||||
|
||||
``draw``
|
||||
Defaults to *False*. Draw the text to the current surface.
|
||||
|
||||
``color``
|
||||
Defaults to *None*. The colour to draw with.
|
||||
"""
|
||||
# setup defaults
|
||||
painter = QtGui.QPainter()
|
||||
@ -424,7 +535,7 @@ class Renderer:
|
||||
else:
|
||||
font = self.mainFont
|
||||
painter.setFont(font)
|
||||
if color == None:
|
||||
if color is None:
|
||||
if footer:
|
||||
painter.setPen(QtGui.QColor(self._theme.font_footer_color))
|
||||
else:
|
||||
@ -443,7 +554,13 @@ class Renderer:
|
||||
|
||||
def snoop_Image(self, image, image2=None):
|
||||
"""
|
||||
Debugging method to allow images to be viewed
|
||||
Debugging method to allow images to be viewed.
|
||||
|
||||
``image``
|
||||
An image to save to disk.
|
||||
|
||||
``image2``
|
||||
Defaults to *None*. Another image to save to disk.
|
||||
"""
|
||||
im = image.toImage()
|
||||
im.save(u'renderer.png', u'png')
|
||||
|
@ -18,26 +18,37 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
import logging
|
||||
import os, os.path
|
||||
import sys
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from renderer import Renderer
|
||||
|
||||
import os
|
||||
import sys
|
||||
import linecache
|
||||
|
||||
class RenderManager:
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from renderer import Renderer
|
||||
|
||||
class RenderManager(object):
|
||||
"""
|
||||
Class to pull all Renderer interactions into one place.
|
||||
The plugins will call helper methods to do the rendering but
|
||||
this class will provide display defense code.
|
||||
Class to pull all Renderer interactions into one place. The plugins will
|
||||
call helper methods to do the rendering but this class will provide
|
||||
display defense code.
|
||||
"""
|
||||
global log
|
||||
log=logging.getLogger(u'RenderManager')
|
||||
log.info(u'RenderManager Loaded')
|
||||
|
||||
def __init__(self, theme_manager, screen_list, screen_number=0):
|
||||
"""
|
||||
Initialise the render manager.
|
||||
|
||||
``theme_manager``
|
||||
The ThemeManager instance, used to get the current theme details.
|
||||
|
||||
``screen_list``
|
||||
The list of screens available.
|
||||
|
||||
``screen_number``
|
||||
Defaults to *0*. The index of the output/display screen.
|
||||
"""
|
||||
log.debug(u'Initilisation started')
|
||||
self.screen_list = screen_list
|
||||
self.theme_manager = theme_manager
|
||||
@ -52,21 +63,46 @@ class RenderManager:
|
||||
def update_display(self, screen_number):
|
||||
"""
|
||||
Updates the render manager's information about the current screen.
|
||||
|
||||
``screen_number``
|
||||
The updated index of the output/display screen.
|
||||
"""
|
||||
log.debug(u'Update Display')
|
||||
if self.current_display != screen_number:
|
||||
self.current_display = screen_number
|
||||
self.calculate_default(self.screen_list[self.current_display][u'size'])
|
||||
|
||||
def set_global_theme(self, global_theme, global_style = u'Global'):
|
||||
def set_global_theme(self, global_theme, global_style=u'Global'):
|
||||
"""
|
||||
Set the global-level theme and the theme level.
|
||||
|
||||
``global_theme``
|
||||
The global-level theme to be set.
|
||||
|
||||
``global_style``
|
||||
Defaults to *"Global"*. The theme level, can be "Global",
|
||||
"Service" or "Song".
|
||||
"""
|
||||
self.global_theme = global_theme
|
||||
self.global_style = global_style
|
||||
|
||||
def set_service_theme(self, service_theme):
|
||||
"""
|
||||
Set the service-level theme.
|
||||
|
||||
``service_theme``
|
||||
The service-level theme to be set.
|
||||
"""
|
||||
self.service_theme = service_theme
|
||||
|
||||
def set_override_theme(self, theme):
|
||||
log.debug(u'set override theme to %s', theme)
|
||||
"""
|
||||
Set the appropriate theme depending on the theme level.
|
||||
|
||||
``theme``
|
||||
The name of the song-level theme.
|
||||
"""
|
||||
log.debug(u'set override theme to %s', theme)
|
||||
if self.global_style == u'Global':
|
||||
self.theme = self.global_theme
|
||||
elif self.global_style == u'Service':
|
||||
@ -84,7 +120,7 @@ class RenderManager:
|
||||
self.theme = self.service_theme
|
||||
else:
|
||||
self.theme = self.global_theme
|
||||
if self.theme is not self.renderer.theme_name:
|
||||
if self.theme != self.renderer.theme_name:
|
||||
log.debug(u'theme is now %s', self.theme)
|
||||
self.themedata = self.theme_manager.getThemeData(self.theme)
|
||||
self.calculate_default(self.screen_list[self.current_display][u'size'])
|
||||
@ -92,7 +128,13 @@ class RenderManager:
|
||||
self.build_text_rectangle(self.themedata)
|
||||
|
||||
def build_text_rectangle(self, theme):
|
||||
log.debug(u'build_text_rectangle ')
|
||||
"""
|
||||
Builds a text block using the settings in ``theme``.
|
||||
|
||||
``theme``
|
||||
The theme to build a text block for.
|
||||
"""
|
||||
log.debug(u'build_text_rectangle')
|
||||
main_rect = None
|
||||
footer_rect = None
|
||||
if theme.font_main_override == False:
|
||||
@ -108,31 +150,52 @@ class RenderManager:
|
||||
self.renderer.set_text_rectangle(main_rect,footer_rect)
|
||||
|
||||
def generate_preview(self, themedata):
|
||||
"""
|
||||
Generate a preview of a theme.
|
||||
|
||||
``themedata``
|
||||
The theme to generated a preview for.
|
||||
"""
|
||||
log.debug(u'generate preview')
|
||||
self.calculate_default(QtCore.QSize(1024, 768))
|
||||
self.renderer.set_theme(themedata)
|
||||
self.build_text_rectangle(themedata)
|
||||
self.renderer.set_frame_dest(self.width, self.height, True)
|
||||
lines = []
|
||||
lines.append(u'Amazing Grace!')
|
||||
lines.append(u'How sweet the sound')
|
||||
lines.append(u'To save a wretch like me;')
|
||||
lines.append(u'I once was lost but now am found,')
|
||||
lines.append(u'Was blind, but now I see.')
|
||||
lines1 = []
|
||||
lines1.append(u'Amazing Grace (John Newton)' )
|
||||
lines1.append(u'Public Domain')
|
||||
lines1.append(u'CCLI xxx')
|
||||
return self.renderer.generate_frame_from_lines(lines, lines1)
|
||||
verse = []
|
||||
verse.append(u'Amazing Grace!')
|
||||
verse.append(u'How sweet the sound')
|
||||
verse.append(u'To save a wretch like me;')
|
||||
verse.append(u'I once was lost but now am found,')
|
||||
verse.append(u'Was blind, but now I see.')
|
||||
footer = []
|
||||
footer.append(u'Amazing Grace (John Newton)' )
|
||||
footer.append(u'Public Domain')
|
||||
footer.append(u'CCLI xxx')
|
||||
return self.renderer.generate_frame_from_lines(verse, footer)
|
||||
|
||||
def format_slide(self, words):
|
||||
"""
|
||||
Calculate how much text can fid on a slide.
|
||||
|
||||
``words``
|
||||
The words to go on the slides.
|
||||
"""
|
||||
log.debug(u'format slide')
|
||||
self.calculate_default(self.screen_list[self.current_display][u'size'])
|
||||
self.build_text_rectangle(self.themedata)
|
||||
self.renderer.set_frame_dest(self.width, self.height)
|
||||
return self.renderer.format_slide(words, False)
|
||||
|
||||
def generate_slide(self,main_text, footer_text):
|
||||
def generate_slide(self, main_text, footer_text):
|
||||
"""
|
||||
Generate the actual slide image.
|
||||
|
||||
``main_text``
|
||||
The text for the main area of the slide.
|
||||
|
||||
``footer_text``
|
||||
The text for the slide footer.
|
||||
"""
|
||||
log.debug(u'generate slide')
|
||||
self.calculate_default(self.screen_list[self.current_display][u'size'])
|
||||
self.build_text_rectangle(self.themedata)
|
||||
@ -140,6 +203,12 @@ class RenderManager:
|
||||
return self.renderer.generate_frame_from_lines(main_text, footer_text)
|
||||
|
||||
def resize_image(self, image):
|
||||
"""
|
||||
Resize an image to fit on the current screen.
|
||||
|
||||
``image``
|
||||
The image to resize.
|
||||
"""
|
||||
preview = QtGui.QImage(image)
|
||||
w = self.width
|
||||
h = self.height
|
||||
@ -154,13 +223,19 @@ class RenderManager:
|
||||
return newImage
|
||||
|
||||
def calculate_default(self, screen):
|
||||
log.debug(u'calculate default %s' , screen)
|
||||
"""
|
||||
Calculate the default dimentions of the screen.
|
||||
|
||||
``screen``
|
||||
The QWidget instance of the screen.
|
||||
"""
|
||||
log.debug(u'calculate default %s', screen)
|
||||
if self.current_display == 0:
|
||||
self.width = 1024
|
||||
self.height = 768
|
||||
else:
|
||||
self.width = screen.width()
|
||||
self.height = screen.height()
|
||||
log.debug(u'calculate default %d,%d' , self.width, self.height)
|
||||
log.debug(u'calculate default %d, %d', self.width, self.height)
|
||||
# 90% is start of footer
|
||||
self.footer_start = int(self.height * 0.90)
|
||||
|
@ -20,10 +20,12 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from openlp.core.lib import buildIcon
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
class ServiceItem():
|
||||
from openlp.core.lib import buildIcon
|
||||
|
||||
class ServiceItem(object):
|
||||
"""
|
||||
The service item is a base class for the plugins to use to interact with
|
||||
the service manager, the slide controller, and the projection screen
|
||||
@ -35,7 +37,10 @@ class ServiceItem():
|
||||
|
||||
def __init__(self, hostplugin=None):
|
||||
"""
|
||||
Init Method
|
||||
Set up the service item.
|
||||
|
||||
``hostplugin``
|
||||
The plugin that this service item belongs to.
|
||||
"""
|
||||
self.plugin = hostplugin
|
||||
if hostplugin is not None:
|
||||
@ -56,6 +61,14 @@ class ServiceItem():
|
||||
self.service_frames = []
|
||||
|
||||
def addIcon(self, icon):
|
||||
"""
|
||||
Add an icon to the service item. This is used when displaying the
|
||||
service item in the service manager.
|
||||
|
||||
``icon``
|
||||
An instance of QIcon or a string to an icon in the resource or on
|
||||
disk.
|
||||
"""
|
||||
self.icon = icon
|
||||
self.iconic_representation = buildIcon(icon)
|
||||
|
||||
@ -89,27 +102,63 @@ class ServiceItem():
|
||||
else:
|
||||
log.error(u'Invalid value renderer :%s' % self.service_item_type)
|
||||
|
||||
def add_from_image(self, path, frame_title, image):
|
||||
def add_from_image(self, path, frame_title, image):
|
||||
"""
|
||||
Add an image slide to the service item.
|
||||
|
||||
``path``
|
||||
The directory in which the image file is located.
|
||||
|
||||
``frame_title``
|
||||
A title for the slide in the service item.
|
||||
|
||||
``image``
|
||||
The actual image file name.
|
||||
"""
|
||||
self.service_item_type = u'image'
|
||||
self.service_item_path = path
|
||||
self.service_frames.append({u'title': frame_title, u'image': image})
|
||||
|
||||
def add_from_text(self, frame_title, raw_slide):
|
||||
"""
|
||||
Add a text slide to the service item.
|
||||
|
||||
``frame_title``
|
||||
The title of the slide in the service item.
|
||||
|
||||
``raw_slide``
|
||||
The raw text of the slide.
|
||||
"""
|
||||
self.service_item_type = u'text'
|
||||
frame_title = frame_title.split(u'\n')[0]
|
||||
self.service_frames.append({u'title': frame_title, u'raw_slide': raw_slide})
|
||||
|
||||
def add_from_command(self, frame_title, command):
|
||||
"""
|
||||
Add a slide from a command.
|
||||
|
||||
``frame_title``
|
||||
The title of the slide in the service item.
|
||||
|
||||
``command``
|
||||
The command of/for the slide.
|
||||
"""
|
||||
self.service_item_type = u'command'
|
||||
self.service_frames.append({u'title': frame_title, u'command': command})
|
||||
|
||||
def get_oos_repr(self):
|
||||
"""
|
||||
This method returns some text which can be saved into the OOS
|
||||
file to represent this item
|
||||
file to represent this item.
|
||||
"""
|
||||
oos_header = {u'plugin': self.shortname,u'theme':self.theme, u'title':self.title,
|
||||
u'icon':self.icon, u'footer':self.raw_footer, u'type':self.service_item_type}
|
||||
oos_header = {
|
||||
u'plugin': self.shortname,
|
||||
u'theme':self.theme,
|
||||
u'title':self.title,
|
||||
u'icon':self.icon,
|
||||
u'footer':self.raw_footer,
|
||||
u'type':self.service_item_type
|
||||
}
|
||||
oos_data = []
|
||||
if self.service_item_type == u'text':
|
||||
for slide in self.service_frames:
|
||||
@ -124,8 +173,14 @@ class ServiceItem():
|
||||
|
||||
def set_from_oos(self, serviceitem, path=None):
|
||||
"""
|
||||
This method takes some oos list (passed from the ServiceManager)
|
||||
and extracts the data actually required
|
||||
This method takes a service item from a saved service file (passed
|
||||
from the ServiceManager) and extracts the data actually required.
|
||||
|
||||
``serviceitem``
|
||||
The item to extract data from.
|
||||
|
||||
``path``
|
||||
Defaults to *None*. Any path data, usually for images.
|
||||
"""
|
||||
#print "sfs", serviceitem
|
||||
header = serviceitem[u'serviceitem'][u'header']
|
||||
|
@ -23,11 +23,20 @@ from openlp.core.lib import PluginConfig
|
||||
|
||||
class SettingsTab(QtGui.QWidget):
|
||||
"""
|
||||
SettingsTab is a helper widget for plugins to define Tabs for the settings dialog.
|
||||
SettingsTab is a helper widget for plugins to define Tabs for the settings
|
||||
dialog.
|
||||
"""
|
||||
def __init__(self, title=None, section=None):
|
||||
"""
|
||||
Constructor to create the Steetings tab item.
|
||||
Constructor to create the Settings tab item.
|
||||
|
||||
``title``
|
||||
Defaults to *None*. The title of the tab, which is usually
|
||||
displayed on the tab.
|
||||
|
||||
``section``
|
||||
Defaults to *None*. This is the section in the configuration file
|
||||
to write to when the ``save`` method is called.
|
||||
"""
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.tabTitle = title
|
||||
@ -43,6 +52,9 @@ class SettingsTab(QtGui.QWidget):
|
||||
def setTitle(self, title):
|
||||
"""
|
||||
Set the title of the tab.
|
||||
|
||||
``title``
|
||||
The title of the tab, which is usually displayed on the tab.
|
||||
"""
|
||||
self.tabTitle = title
|
||||
|
||||
|
@ -30,21 +30,34 @@ from xml.etree.ElementTree import ElementTree, XML, dump
|
||||
|
||||
"""
|
||||
import logging
|
||||
from xml.dom.minidom import Document
|
||||
from xml.dom.minidom import Document
|
||||
from xml.etree.ElementTree import ElementTree, XML, dump
|
||||
|
||||
class SongXMLBuilder():
|
||||
"""
|
||||
This class builds the XML used to describe songs.
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
Set up the song builder.
|
||||
"""
|
||||
# Create the minidom document
|
||||
self.song_xml = Document()
|
||||
|
||||
def new_document(self):
|
||||
"""
|
||||
Create a new song XML document.
|
||||
"""
|
||||
# Create the <song> base element
|
||||
self.song = self.song_xml.createElement(u'song')
|
||||
self.song_xml.appendChild(self.song)
|
||||
self.song.setAttribute(u'version', u'1.0')
|
||||
|
||||
def add_lyrics_to_song(self):
|
||||
"""
|
||||
Set up and add a ``<lyrics>`` tag which contains the lyrics of the
|
||||
song.
|
||||
"""
|
||||
# Create the main <lyrics> element
|
||||
self.lyrics = self.song_xml.createElement(u'lyrics')
|
||||
self.lyrics.setAttribute(u'language', u'en')
|
||||
@ -52,50 +65,72 @@ class SongXMLBuilder():
|
||||
|
||||
def add_verse_to_lyrics(self, type, number, content):
|
||||
"""
|
||||
type - type of verse (Chorus, Verse , Bridge, Custom etc
|
||||
number - number of item eg verse 1
|
||||
content - the text to be stored
|
||||
Add a verse to the ``<lyrics>`` tag.
|
||||
|
||||
``type``
|
||||
A string denoting the type of verse. Possible values are "Chorus",
|
||||
"Verse", "Bridge", and "Custom".
|
||||
|
||||
``number``
|
||||
An integer denoting the number of the item, for example: verse 1.
|
||||
|
||||
``content``
|
||||
The actual text of the verse to be stored.
|
||||
"""
|
||||
verse = self.song_xml.createElement(u'verse')
|
||||
verse.setAttribute(u'type', type)
|
||||
verse.setAttribute(u'label', number)
|
||||
self.lyrics.appendChild(verse)
|
||||
|
||||
# add data as a CDATA section
|
||||
# add data as a CDATA section to protect the XML from special chars
|
||||
cds = self.song_xml.createCDATASection(content)
|
||||
verse.appendChild(cds)
|
||||
|
||||
def dump_xml(self):
|
||||
# Debugging aid to see what we have
|
||||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
print self.song_xml.toprettyxml(indent=u' ')
|
||||
|
||||
def extract_xml(self):
|
||||
# Print our newly created XML
|
||||
"""
|
||||
Extract our newly created XML song.
|
||||
"""
|
||||
return self.song_xml.toxml(u'utf-8')
|
||||
|
||||
class SongXMLParser():
|
||||
"""
|
||||
A class to read in and parse a song's XML.
|
||||
"""
|
||||
global log
|
||||
log = logging.getLogger(u'SongXMLParser')
|
||||
log.info(u'SongXMLParser Loaded')
|
||||
|
||||
def __init__(self, xml):
|
||||
#print xml
|
||||
"""
|
||||
Set up our song XML parser.
|
||||
|
||||
``xml``
|
||||
The XML of the song to be parsed.
|
||||
"""
|
||||
try:
|
||||
self.song_xml = ElementTree(element=XML(xml))
|
||||
except:
|
||||
#print "invalid xml ", xml
|
||||
log.debug(u'invalid xml %s', xml)
|
||||
log.debug(u'Invalid xml %s', xml)
|
||||
|
||||
def get_verses(self):
|
||||
#return a list of verse's and attributes
|
||||
iter=self.song_xml.getiterator()
|
||||
"""
|
||||
Iterates through the verses in the XML and returns a list of verses
|
||||
and their attributes.
|
||||
"""
|
||||
iter = self.song_xml.getiterator()
|
||||
verse_list = []
|
||||
for element in iter:
|
||||
#print element.tag, element.attrib, element.text
|
||||
if element.tag == u'verse':
|
||||
verse_list.append([element.attrib, element.text])
|
||||
return verse_list
|
||||
|
||||
def dump_xml(self):
|
||||
# Debugging aid to see what we have
|
||||
"""
|
||||
Debugging aid to dump XML so that we can see what we have.
|
||||
"""
|
||||
print dump(self.song_xml)
|
||||
|
@ -345,5 +345,5 @@ class ThemeXML(object):
|
||||
s = u''
|
||||
for k in dir(self):
|
||||
if k[0:1] != u'_':
|
||||
s += u'%30s : %s\n' %(k, getattr(self, k))
|
||||
s += u'%30s: %s\n' %(k, getattr(self, k))
|
||||
return s
|
||||
|
Loading…
Reference in New Issue
Block a user