diff --git a/openlp.pyw b/openlp.pyw index e1085d545..58925fdb9 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -28,13 +28,13 @@ import os import sys import logging -from logging.handlers import RotatingFileHandler +from logging import FileHandler from optparse import OptionParser from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, str_to_bool from openlp.core.resources import qInitResources -from openlp.core.ui import MainWindow, SplashScreen +from openlp.core.ui import MainWindow, SplashScreen, ScreenList from openlp.core.utils import ConfigHelper log = logging.getLogger() @@ -68,6 +68,10 @@ class OpenLP(QtGui.QApplication): global log log.info(u'OpenLP Application Loaded') + def notify(self, obj, evt): + #TODO needed for presentation exceptions + return QtGui.QApplication.notify(self, obj, evt) + def run(self): """ Run the OpenLP application. @@ -117,10 +121,10 @@ class OpenLP(QtGui.QApplication): self.splash.show() # make sure Qt really display the splash screen self.processEvents() - screens = [] + screens = ScreenList() # Decide how many screens we have and their size for screen in xrange(0, self.desktop().numScreens()): - screens.append({u'number': screen, + screens.add_screen({u'number': screen, u'size': self.desktop().availableGeometry(screen), u'primary': (self.desktop().primaryScreen() == screen)}) log.info(u'Screen %d found with resolution %s', @@ -131,6 +135,7 @@ class OpenLP(QtGui.QApplication): if show_splash: # now kill the splashscreen self.splash.finish(self.mainWindow) + self.mainWindow.repaint() self.mainWindow.versionCheck() return self.exec_() @@ -154,7 +159,7 @@ def main(): help="Set the Qt4 style (passed directly to Qt4).") # Set up logging filename = u'openlp.log' - logfile = RotatingFileHandler(filename, maxBytes=200000, backupCount=5) + logfile = FileHandler(filename) logfile.setFormatter(logging.Formatter( u'%(asctime)s %(name)-15s %(levelname)-8s %(message)s')) log.addHandler(logfile) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 22df9a926..93512f946 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -136,6 +136,26 @@ def contextMenuSeparator(base): action.setSeparator(True) return action +def resize_image(image, width, height): + """ + Resize an image to fit on the current screen. + + ``image`` + The image to resize. + """ + preview = QtGui.QImage(image) + preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio, + QtCore.Qt.SmoothTransformation) + realw = preview.width(); + realh = preview.height() + # and move it to the centre of the preview space + newImage = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32_Premultiplied) + newImage.fill(QtCore.Qt.black) + painter = QtGui.QPainter(newImage) + painter.drawImage((width - realw) / 2, (height - realh) / 2, preview) + return newImage + + class ThemeLevel(object): Global = 1 Service = 2 @@ -160,6 +180,3 @@ from renderer import Renderer from rendermanager import RenderManager from mediamanageritem import MediaManagerItem from baselistwithdnd import BaseListWithDnD - -#__all__ = [ 'translate', 'get_text_file_string', 'str_to_bool', -# 'contextMenuAction', 'contextMenuSeparator', 'ServiceItem'] \ No newline at end of file diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index c4d7444c4..cc976dae5 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -26,6 +26,7 @@ import logging from PyQt4 import QtGui, QtCore +from openlp.core.lib import resize_image class Renderer(object): """ @@ -41,7 +42,7 @@ class Renderer(object): Initialise the renderer. """ self._rect = None - self._debug = 0 + self._debug = False self._right_margin = 64 # the amount of right indent self._display_shadow_size_footer = 0 self._display_outline_size_footer = 0 @@ -90,31 +91,9 @@ class Renderer(object): log.debug(u'set bg image %s', filename) self._bg_image_filename = unicode(filename) if self._frame: - 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() - height = self._frame.height() - preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio, - QtCore.Qt.SmoothTransformation) - realwidth = preview.width() - realheight = preview.height() - # and move it to the centre of the preview space - self.bg_image = QtGui.QImage(width, height, - QtGui.QImage.Format_ARGB32_Premultiplied) - self.bg_image.fill(QtCore.Qt.black) - painter = QtGui.QPainter() - painter.begin(self.bg_image) - self.background_offsetx = (width - realwidth) / 2 - self.background_offsety = (height - realheight) / 2 - painter.drawImage(self.background_offsetx, - self.background_offsety, preview) - painter.end() + self.bg_image = resize_image(self._bg_image_filename, + self._frame.width(), + self._frame.height()) def set_frame_dest(self, frame_width, frame_height, preview=False): """ @@ -138,7 +117,9 @@ class Renderer(object): self._frameOp = QtGui.QImage(frame_width, frame_height, QtGui.QImage.Format_ARGB32_Premultiplied) if self._bg_image_filename and not self.bg_image: - self.scale_bg_image() + self.bg_image = resize_image(self._bg_image_filename, + self._frame.width(), + self._frame.height()) if self.bg_frame is None: self._generate_background_frame() @@ -167,17 +148,22 @@ class Renderer(object): def pre_render_text(self, text): metrics = QtGui.QFontMetrics(self.mainFont) - #take the width work out approx how many characters and add 50% + #work out line width line_width = self._rect.width() - self._right_margin #number of lines on a page - adjust for rounding up. - page_length = int(self._rect.height() / metrics.height() - 2 ) - 1 + line_height = metrics.height() + if self._theme.display_shadow: + line_height += int(self._theme.display_shadow_size) + if self._theme.display_outline: + # pixels top/bottom + line_height += 2 * int(self._theme.display_outline_size) + page_length = int(self._rect.height() / line_height ) #Average number of characters in line ave_line_width = line_width / metrics.averageCharWidth() #Maximum size of a character max_char_width = metrics.maxWidth() - #Min size of a character - min_char_width = metrics.width(u'i') - char_per_line = line_width / min_char_width + #Max characters pre line based on min size of a character + char_per_line = line_width / metrics.width(u'i') log.debug(u'Page Length area height %s , metrics %s , lines %s' % (int(self._rect.height()), metrics.height(), page_length )) split_pages = [] @@ -276,8 +262,13 @@ class Renderer(object): Results are cached for performance reasons. """ assert(self._theme) - self.bg_frame = QtGui.QImage(self._frame.width(), self._frame.height(), - QtGui.QImage.Format_ARGB32_Premultiplied) + if self._theme.background_mode == u'transparent': + self.bg_frame = \ + QtGui.QPixmap(self._frame.width(), self._frame.height()) + self.bg_frame.fill(QtCore.Qt.transparent) + else: + self.bg_frame = QtGui.QImage(self._frame.width(), self._frame.height(), + QtGui.QImage.Format_ARGB32_Premultiplied) log.debug(u'render background %s start', self._theme.background_type) painter = QtGui.QPainter() painter.begin(self.bg_frame) @@ -422,6 +413,14 @@ class Renderer(object): startx = x starty = y rightextent = None + self.painter = QtGui.QPainter() + self.painter.begin(self._frame) + self.painter.setRenderHint(QtGui.QPainter.Antialiasing); + if self._theme.display_slideTransition: + self.painter2 = QtGui.QPainter() + self.painter2.begin(self._frameOp) + self.painter2.setRenderHint(QtGui.QPainter.Antialiasing); + self.painter2.setOpacity(0.7) # dont allow alignment messing with footers if footer: align = 0 @@ -503,13 +502,14 @@ class Renderer(object): if linenum == 0: self._first_line_right_extent = rightextent # draw a box around the text - debug only + if self._debug: - painter = QtGui.QPainter() - painter.begin(self._frame) - painter.setPen(QtGui.QPen(QtGui.QColor(0,255,0))) - painter.drawRect(startx, starty, rightextent-startx, y-starty) - painter.end() + self.painter.setPen(QtGui.QPen(QtGui.QColor(0,255,0))) + self.painter.drawRect(startx, starty, rightextent-startx, y-starty) brcorner = (rightextent, y) + self.painter.end() + if self._theme.display_slideTransition: + self.painter2.end() return brcorner def _set_theme_font(self): @@ -519,6 +519,7 @@ class Renderer(object): footer_weight = 50 if self._theme.font_footer_weight == u'Bold': footer_weight = 75 + #TODO Add myfont.setPixelSize((screen_height / 100) * font_size) self.footerFont = QtGui.QFont(self._theme.font_footer_name, self._theme.font_footer_proportion, # size footer_weight, # weight @@ -556,45 +557,36 @@ class Renderer(object): Defaults to *None*. The colour to draw with. """ # setup defaults - painter = QtGui.QPainter() - painter.begin(self._frame) - painter.setRenderHint(QtGui.QPainter.Antialiasing); if footer : font = self.footerFont else: font = self.mainFont - painter.setFont(font) + self.painter.setFont(font) if color is None: if footer: - painter.setPen(QtGui.QColor(self._theme.font_footer_color)) + self.painter.setPen(QtGui.QColor(self._theme.font_footer_color)) else: - painter.setPen(QtGui.QColor(self._theme.font_main_color)) + self.painter.setPen(QtGui.QColor(self._theme.font_main_color)) else: - painter.setPen(QtGui.QColor(color)) + self.painter.setPen(QtGui.QColor(color)) x, y = tlcorner metrics = QtGui.QFontMetrics(font) w = metrics.width(line) - h = metrics.height() - 2 + h = metrics.height() if draw: - painter.drawText(x, y + metrics.ascent(), line) - painter.end() + self.painter.drawText(x, y + metrics.ascent(), line) if self._theme.display_slideTransition: # Print 2nd image with 70% weight - painter = QtGui.QPainter() - painter.begin(self._frameOp) - painter.setRenderHint(QtGui.QPainter.Antialiasing); - painter.setOpacity(0.7) - painter.setFont(font) + self.painter2.setFont(font) if color is None: if footer: - painter.setPen(QtGui.QColor(self._theme.font_footer_color)) + self.painter2.setPen(QtGui.QColor(self._theme.font_footer_color)) else: - painter.setPen(QtGui.QColor(self._theme.font_main_color)) + self.painter2.setPen(QtGui.QColor(self._theme.font_main_color)) else: - painter.setPen(QtGui.QColor(color)) + self.painter2.setPen(QtGui.QColor(color)) if draw: - painter.drawText(x, y + metrics.ascent(), line) - painter.end() + self.painter2.drawText(x, y + metrics.ascent(), line) return (w, h) def snoop_Image(self, image, image2=None): @@ -609,4 +601,4 @@ class Renderer(object): """ image.save(u'renderer.png', u'png') if image2: - image2.save(u'renderer2.png', u'png') \ No newline at end of file + image2.save(u'renderer2.png', u'png') diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index a0e2ce0af..600a029c0 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtGui, QtCore from renderer import Renderer -from openlp.core.lib import ThemeLevel +from openlp.core.lib import ThemeLevel, resize_image class RenderManager(object): """ @@ -39,8 +39,8 @@ class RenderManager(object): ``theme_manager`` The ThemeManager instance, used to get the current theme details. - ``screen_list`` - The list of screens available. + ``screens`` + Contains information about the Screens. ``screen_number`` Defaults to *0*. The index of the output/display screen. @@ -49,27 +49,21 @@ class RenderManager(object): log = logging.getLogger(u'RenderManager') log.info(u'RenderManager Loaded') - def __init__(self, theme_manager, screen_list, screen_number=0): + def __init__(self, theme_manager, screens, screen_number=0): """ Initialise the render manager. """ log.debug(u'Initilisation started') - self.screen_list = screen_list + self.screens = screens self.theme_manager = theme_manager - self.displays = len(screen_list) - if (screen_number + 1) > len(screen_list): - self.current_display = 0 - else: - self.current_display = screen_number self.renderer = Renderer() - self.calculate_default(self.screen_list[self.current_display][u'size']) + self.screens.set_current_display(screen_number) + self.calculate_default(self.screens.current[u'size']) self.theme = u'' self.service_theme = u'' self.theme_level = u'' self.override_background = None self.themedata = None - self.save_bg_frame = None - self.override_background_changed = False def update_display(self, screen_number): """ @@ -79,10 +73,8 @@ class RenderManager(object): 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']) + self.calculate_default(self.screens.current[u'size']) + self.renderer.bg_frame = None def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global): """ @@ -137,31 +129,14 @@ class RenderManager(object): if self.theme != self.renderer.theme_name or self.themedata is None: 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']) + self.calculate_default(self.screens.current[u'size']) self.renderer.set_theme(self.themedata) self.build_text_rectangle(self.themedata) - #Replace the backgrount image from renderer with one from image - if self.override_background: - if self.save_bg_frame is None: - self.save_bg_frame = self.renderer.bg_frame - if self.override_background_changed: - self.renderer.bg_frame = self.resize_image( - self.override_background) - self.override_background_changed = False - else: - if self.override_background_changed: - self.renderer.bg_frame = self.resize_image( - self.override_background) - self.override_background_changed = False - if self.save_bg_frame: - self.renderer.bg_frame = self.save_bg_frame - self.save_bg_frame = None def build_text_rectangle(self, theme): """ - Builds a text block using the settings in ``theme``. - One is needed per slide + Builds a text block using the settings in ``theme`` + and the size of the display screen.height. ``theme`` The theme to build a text block for. @@ -170,14 +145,14 @@ class RenderManager(object): main_rect = None footer_rect = None if not theme.font_main_override: - main_rect = QtCore.QRect(10, 0, self.width - 1, - self.footer_start - 20) + main_rect = QtCore.QRect(10, 0, + self.width - 1, self.footer_start) else: main_rect = QtCore.QRect(theme.font_main_x, theme.font_main_y, theme.font_main_width - 1, theme.font_main_height - 1) if not theme.font_footer_override: - footer_rect = QtCore.QRect(10, self.footer_start, self.width - 1, - self.height-self.footer_start) + footer_rect = QtCore.QRect(10, self.footer_start, + self.width - 1, self.height - self.footer_start) else: footer_rect = QtCore.QRect(theme.font_footer_x, theme.font_footer_y, theme.font_footer_width - 1, @@ -192,10 +167,13 @@ class RenderManager(object): The theme to generated a preview for. """ log.debug(u'generate preview') - self.calculate_default(QtCore.QSize(1024, 768)) + #set the default image size for previews + self.calculate_default(self.screens.preview[u'size']) self.renderer.set_theme(themedata) self.build_text_rectangle(themedata) self.renderer.set_frame_dest(self.width, self.height, True) + #Reset the real screen size for subsequent render requests + self.calculate_default(self.screens.current[u'size']) verse = u'Amazing Grace!\n'\ 'How sweet the sound\n'\ 'To save a wretch like me;\n'\ @@ -206,6 +184,7 @@ class RenderManager(object): footer.append(u'Public Domain') footer.append(u'CCLI 123456') formatted = self.renderer.format_slide(verse, False) + #Only Render the first slide page returned return self.renderer.generate_frame_from_lines(formatted[0], footer)[u'main'] def format_slide(self, words): @@ -234,48 +213,18 @@ class RenderManager(object): self.renderer.set_frame_dest(self.width, self.height) return self.renderer.generate_frame_from_lines(main_text, footer_text) - def resize_image(self, image, width=0, height=0): - """ - Resize an image to fit on the current screen. - - ``image`` - The image to resize. - """ - preview = QtGui.QImage(image) - if width == 0: - w = self.width - h = self.height - else: - w = width - h = height - preview = preview.scaled(w, h, QtCore.Qt.KeepAspectRatio, - QtCore.Qt.SmoothTransformation) - realw = preview.width(); - realh = preview.height() - # and move it to the centre of the preview space - newImage = QtGui.QImage(w, h, QtGui.QImage.Format_ARGB32_Premultiplied) - newImage.fill(QtCore.Qt.black) - painter = QtGui.QPainter(newImage) - painter.drawImage((w - realw) / 2, (h - realh) / 2, preview) - return newImage - def calculate_default(self, screen): """ Calculate the default dimentions of the screen. ``screen`` - The QWidget instance of the screen. + The QSize of the screen. """ log.debug(u'calculate default %s', screen) - #size fixed so reflects the preview size. - if self.current_display == 0: - self.width = 1024 - self.height = 768 - else: - self.width = screen.width() - self.height = screen.height() + self.width = screen.width() + self.height = screen.height() self.screen_ratio = float(self.height) / float(self.width) log.debug(u'calculate default %d, %d, %f', self.width, self.height, self.screen_ratio ) # 90% is start of footer - self.footer_start = int(self.height * 0.90) \ No newline at end of file + self.footer_start = int(self.height * 0.90) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 004973462..603d7cadb 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -30,7 +30,7 @@ import uuid from PyQt4 import QtGui -from openlp.core.lib import build_icon, Receiver +from openlp.core.lib import build_icon, Receiver, resize_image class ServiceItemType(object): """ @@ -102,16 +102,19 @@ class ServiceItem(object): formated = self.RenderManager.format_slide(slide[u'raw_slide']) for format in formated: lines = u'' + title = u'' for line in format: + if title == u'': + title = line lines += line + u'\n' - title = lines.split(u'\n')[0] self._display_frames.append({u'title': title, \ - u'text': lines, u'verseTag': slide[u'verseTag'] }) + u'text': lines.rstrip(), u'verseTag': slide[u'verseTag'] }) log.log(15, u'Formatting took %4s' % (time.time() - before)) elif self.service_item_type == ServiceItemType.Image: for slide in self._raw_frames: slide[u'image'] = \ - self.RenderManager.resize_image(slide[u'image']) + resize_image(slide[u'image'], self.RenderManager.width, + self.RenderManager.height) elif self.service_item_type == ServiceItemType.Command: pass else: @@ -119,7 +122,7 @@ class ServiceItem(object): def render_individual(self, row): """ - Takes an array of text and geneates an Image from the + Takes an array of text and generates an Image from the theme. It assumes the text will fit on the screen as it has generated by the render method above. """ @@ -309,4 +312,4 @@ class ServiceItem(object): def request_audit(self): if self.audit: - Receiver.send_message(u'songusage_live', self.audit) \ No newline at end of file + Receiver.send_message(u'songusage_live', self.audit) diff --git a/openlp/core/lib/settingsmanager.py b/openlp/core/lib/settingsmanager.py index 580ec9b31..be5c14af1 100644 --- a/openlp/core/lib/settingsmanager.py +++ b/openlp/core/lib/settingsmanager.py @@ -33,7 +33,7 @@ class SettingsManager(object): individual components. """ def __init__(self, screen): - self.screen = screen[0] + self.screen = screen.current self.width = self.screen[u'size'].width() self.height = self.screen[u'size'].height() self.mainwindow_height = self.height * 0.8 @@ -72,4 +72,4 @@ class SettingsManager(object): u'media manager', isVisible) def togglePreviewPanel(self, isVisible): - ConfigHelper.set_config(u'user interface', u'preview panel', isVisible) \ No newline at end of file + ConfigHelper.set_config(u'user interface', u'preview panel', isVisible) diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 6b187f5fc..42f232638 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -23,7 +23,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -#from slidecontroller import MasterToolbar +from screen import ScreenList from maindisplay import MainDisplay from amendthemeform import AmendThemeForm from slidecontroller import SlideController @@ -42,4 +42,4 @@ from mainwindow import MainWindow __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainWindow', 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager', - 'AmendThemeForm', 'MediaDockManager', 'ThemeLevel'] \ No newline at end of file + 'AmendThemeForm', 'MediaDockManager', 'ThemeLevel'] diff --git a/openlp/core/ui/amendthemeform.py b/openlp/core/ui/amendthemeform.py index 24a22a7cf..97eecd1e8 100644 --- a/openlp/core/ui/amendthemeform.py +++ b/openlp/core/ui/amendthemeform.py @@ -694,8 +694,14 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog): if self.allowPreview: #calculate main number of rows metrics = self._getThemeMetrics() + line_height = metrics.height() + if self.theme.display_shadow: + line_height += int(self.theme.display_shadow_size) + if self.theme.display_outline: + # pixels top/bottom + line_height += 2 * int(self.theme.display_outline_size) page_length = \ - (self.FontMainHeightSpinBox.value() / metrics.height() - 2) - 1 + ((self.FontMainHeightSpinBox.value()) / line_height ) log.debug(u'Page Length area height %s, metrics %s, lines %s' % (self.FontMainHeightSpinBox.value(), metrics.height(), page_length)) @@ -719,4 +725,4 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog): if self.theme.font_main_width < metrics.maxWidth() * 2 + 64: self.theme.font_main_width = metrics.maxWidth() * 2 + 64 self.FontMainWidthSpinBox.setValue(self.theme.font_main_width) - return metrics \ No newline at end of file + return metrics diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index b5abc2a2e..d821c0f45 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -183,7 +183,7 @@ class GeneralTab(SettingsTab): self.Password = self.PasswordEdit.displayText() def load(self): - for screen in self.screen_list: + for screen in self.screen_list.screen_list: screen_name = u'%s %d' % (self.trUtf8('Screen'), screen[u'number'] + 1) if screen[u'primary']: screen_name = u'%s (%s)' % (screen_name, self.trUtf8('primary')) @@ -215,4 +215,4 @@ class GeneralTab(SettingsTab): self.config.set_config(u'save prompt', self.PromptSaveService) self.config.set_config(u'ccli number', self.CCLINumber) self.config.set_config(u'songselect username', self.Username) - self.config.set_config(u'songselect password', self.Password) \ No newline at end of file + self.config.set_config(u'songselect password', self.Password) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 46da99ac2..cda5774d6 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -30,7 +30,7 @@ import time from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon -from openlp.core.lib import Receiver +from openlp.core.lib import Receiver, resize_image class DisplayWidget(QtGui.QWidget): """ @@ -90,29 +90,28 @@ class MainDisplay(DisplayWidget): self.parent = parent self.setWindowTitle(u'OpenLP Display') self.screens = screens - self.layout = QtGui.QVBoxLayout(self) - self.layout.setSpacing(0) - self.layout.setMargin(0) - self.layout.setObjectName(u'layout') self.mediaObject = Phonon.MediaObject(self) self.video = Phonon.VideoWidget() self.video.setVisible(False) self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) Phonon.createPath(self.mediaObject, self.video) Phonon.createPath(self.mediaObject, self.audio) - self.layout.insertWidget(0, self.video) - self.display = QtGui.QLabel(self) - self.display.setScaledContents(True) - self.layout.insertWidget(0, self.display) + self.display_image = QtGui.QLabel(self) + self.display_image.setScaledContents(True) + self.display_text = QtGui.QLabel(self) + self.display_text.setScaledContents(True) + self.display_alert = QtGui.QLabel(self) + self.display_alert.setScaledContents(True) self.primary = True self.displayBlank = False self.blankFrame = None self.frame = None - self.alertactive = False self.timer_id = 0 self.firstTime = True self.mediaLoaded = False self.hasTransition = False + self.alertList = [] + self.mediaBackground = False QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'alert_text'), self.displayAlert) QtCore.QObject.connect(Receiver.get_receiver(), @@ -126,11 +125,10 @@ class MainDisplay(DisplayWidget): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_play'), self.onMediaPlay) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'media_pause'), self.onMediaPaws) + QtCore.SIGNAL(u'media_pause'), self.onMediaPause) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_stop'), self.onMediaStop) - def setup(self, screenNumber): """ Sets up the screen on a particular screen. @@ -138,38 +136,51 @@ class MainDisplay(DisplayWidget): """ log.debug(u'Setup %s for %s ' %(self.screens, screenNumber)) self.setVisible(False) - screen = self.screens[screenNumber] - if screen[u'number'] != screenNumber: - # We will most probably never actually hit this bit, but just in - # case the index in the list doesn't match the screen number, we - # search for it. - for scrn in self.screens: - if scrn[u'number'] == screenNumber: - screen = scrn - break - self.setGeometry(screen[u'size']) + self.screen = self.screens.current + #Sort out screen locations and sizes + self.setGeometry(self.screen[u'size']) + self.alertScreenPosition = self.screen[u'size'].height() * 0.9 + self.alertHeight = self.screen[u'size'].height() - self.alertScreenPosition + self.display_alert.setGeometry( + QtCore.QRect(0, self.alertScreenPosition, + self.screen[u'size'].width(),self.alertHeight)) + self.video.setGeometry(self.screen[u'size']) + self.display_image.resize(self.screen[u'size'].width(), + self.screen[u'size'].height()) + self.display_text.resize(self.screen[u'size'].width(), + self.screen[u'size'].height()) #Build a custom splash screen self.InitialFrame = QtGui.QImage( - screen[u'size'].width(), screen[u'size'].height(), + self.screen[u'size'].width(), + self.screen[u'size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png') painter_image = QtGui.QPainter() painter_image.begin(self.InitialFrame) painter_image.fillRect(self.InitialFrame.rect(), QtCore.Qt.white) painter_image.drawImage( - (screen[u'size'].width() - splash_image.width()) / 2, - (screen[u'size'].height() - splash_image.height()) / 2, + (self.screen[u'size'].width() - splash_image.width()) / 2, + (self.screen[u'size'].height() - splash_image.height()) / 2, splash_image) - self.frameView(self.InitialFrame) + self.display_image.setPixmap(QtGui.QPixmap.fromImage(self.InitialFrame)) + self.repaint() #Build a Black screen painter = QtGui.QPainter() self.blankFrame = QtGui.QImage( - screen[u'size'].width(), screen[u'size'].height(), + self.screen[u'size'].width(), + self.screen[u'size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) painter.begin(self.blankFrame) - painter.fillRect(self.blankFrame.rect(), QtCore.Qt.black) + #TODO make black when testing finished + painter.fillRect(self.blankFrame.rect(), QtCore.Qt.red) + #build a blank transparent image + self.transparent = QtGui.QPixmap(self.screen[u'size'].width(), + self.screen[u'size'].height()) + self.transparent.fill(QtCore.Qt.transparent) + self.display_alert.setPixmap(self.transparent) + self.frameView(self.transparent) # To display or not to display? - if not screen[u'primary']: + if not self.screen[u'primary']: self.showFullScreen() self.primary = False else: @@ -179,6 +190,8 @@ class MainDisplay(DisplayWidget): def resetDisplay(self): if self.primary: self.setVisible(False) + else: + self.showFullScreen() def hideDisplay(self): self.setVisible(False) @@ -186,6 +199,17 @@ class MainDisplay(DisplayWidget): def showDisplay(self): if not self.primary: self.setVisible(True) + self.showFullScreen() + + def addImageWithText(self, frame): + frame = resize_image(frame, + self.screen[u'size'].width(), + self.screen[u'size'].height() ) + self.display_image.setPixmap(QtGui.QPixmap.fromImage(frame)) +# self.display_image.show() +# if not self.isVisible(): +# self.setVisible(True) +# self.showFullScreen() def frameView(self, frame, transition=False): """ @@ -194,38 +218,38 @@ class MainDisplay(DisplayWidget): ``frame`` Image frame to be rendered """ - if self.timer_id != 0 : - self.displayAlert() - elif not self.displayBlank: + if not self.displayBlank: if transition: - if self.hasTransition: - if self.frame[u'trans'] is not None: - self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame[u'trans'])) - self.repaint() - if frame[u'trans'] is not None: - self.display.setPixmap(QtGui.QPixmap.fromImage(frame[u'trans'])) - self.repaint() - self.hasTransition = True - self.display.setPixmap(QtGui.QPixmap.fromImage(frame[u'main'])) + if self.frame is not None: + self.display_text.setPixmap(QtGui.QPixmap.fromImage(self.frame)) + self.repaint() + self.frame = None + if frame[u'trans'] is not None: + self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame[u'trans'])) + self.repaint() + self.frame = frame[u'trans'] + self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame[u'main'])) + self.display_frame = frame[u'main'] self.repaint() else: - self.display.setPixmap(QtGui.QPixmap.fromImage(frame)) + if isinstance(frame, QtGui.QPixmap): + self.display_text.setPixmap(frame) + else: + self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame)) + self.display_frame = frame if not self.isVisible(): self.setVisible(True) self.showFullScreen() - self.frame = frame def blankDisplay(self, blanked=True): if blanked: self.displayBlank = True - self.display.setPixmap(QtGui.QPixmap.fromImage(self.blankFrame)) + self.display_text.setPixmap(QtGui.QPixmap.fromImage(self.blankFrame)) else: self.displayBlank = False - if self.frame: - self.frameView(self.frame) - if blanked != self.parent.LiveController.blankButton.isChecked(): - self.parent.LiveController.blankButton.setChecked(self.displayBlank) - self.parent.generalConfig.set_config(u'screen blank', self.displayBlank) + if self.display_frame: + self.frameView(self.display_frame) + def displayAlert(self, text=u''): """ @@ -235,17 +259,30 @@ class MainDisplay(DisplayWidget): display text """ log.debug(u'display alert called %s' % text) + self.parent.StatusBar.showMessage(self.trUtf8(u'')) + self.alertList.append(text) + if self.timer_id != 0 or self.mediaLoaded: + self.parent.StatusBar.showMessage(\ + self.trUtf8(u'Alert message created and delayed')) + return + self.generateAlert() + + def generateAlert(self): + log.debug(u'Generate Alert called') + if len(self.alertList) == 0: + return + text = self.alertList.pop(0) alertTab = self.parent.settingsForm.AlertsTab - if isinstance(self.frame, QtGui.QImage): - alertframe = QtGui.QPixmap.fromImage(self.frame) - else: - alertframe = QtGui.QPixmap.fromImage(self.frame[u'main']) + alertframe = \ + QtGui.QPixmap(self.screen[u'size'].width(), self.alertHeight) + alertframe.fill(QtCore.Qt.transparent) painter = QtGui.QPainter(alertframe) - top = alertframe.rect().height() * 0.9 + painter.fillRect(alertframe.rect(), QtCore.Qt.transparent) + painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.fillRect( QtCore.QRect( - 0, top, alertframe.rect().width(), - alertframe.rect().height() - top), + 0, 0, alertframe.rect().width(), + alertframe.rect().height()), QtGui.QColor(alertTab.bg_color)) font = QtGui.QFont() font.setFamily(alertTab.font_face) @@ -253,28 +290,29 @@ class MainDisplay(DisplayWidget): font.setPointSize(40) painter.setFont(font) painter.setPen(QtGui.QColor(alertTab.font_color)) - x, y = (0, top) + x, y = (0, 0) metrics = QtGui.QFontMetrics(font) painter.drawText( x, y + metrics.height() - metrics.descent() - 1, text) painter.end() - self.display.setPixmap(alertframe) + self.display_alert.setPixmap(alertframe) + self.display_alert.setVisible(True) # check to see if we have a timer running if self.timer_id == 0: self.timer_id = self.startTimer(int(alertTab.timeout) * 1000) def timerEvent(self, event): if event.timerId() == self.timer_id: - if isinstance(self.frame, QtGui.QImage): - self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame)) - else: - self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame[u'main'])) - self.killTimer(self.timer_id) - self.timer_id = 0 + self.display_alert.setPixmap(self.transparent) + self.killTimer(self.timer_id) + self.timer_id = 0 + self.generateAlert() def onMediaQueue(self, message): log.debug(u'Queue new media message %s' % message) - self.display.close() + self.display_image.close() + self.display_text.close() + self.display_alert.close() file = os.path.join(message[1], message[2]) if self.firstTime: self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) @@ -287,29 +325,33 @@ class MainDisplay(DisplayWidget): log.debug(u'Play the new media, Live ') if not self.mediaLoaded and not self.displayBlank: self.blankDisplay() + self.display_frame = self.blankFrame self.firstTime = True self.mediaLoaded = True - self.display.hide() + self.display_image.hide() + self.display_text.hide() + self.display_alert.hide() self.video.setFullScreen(True) self.video.setVisible(True) self.mediaObject.play() - if self.primary: - self.setVisible(True) + self.setVisible(True) + self.hide() - def onMediaPaws(self): + def onMediaPause(self): log.debug(u'Media paused by user') self.mediaObject.pause() def onMediaStop(self): log.debug(u'Media stopped by user') self.mediaObject.stop() + self.onMediaFinish() def onMediaFinish(self): log.debug(u'Reached end of media playlist') - if self.primary: - self.setVisible(False) self.mediaObject.stop() self.mediaObject.clearQueue() self.mediaLoaded = False self.video.setVisible(False) - self.display.show() \ No newline at end of file + self.display_text.show() + self.display_image.show() + self.blankDisplay(False) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 854811484..226c629e8 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -50,7 +50,6 @@ media_manager_style = """ border-color: palette(light); } """ - class Ui_MainWindow(object): def setupUi(self, MainWindow): """ @@ -425,7 +424,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): plugins. """ QtGui.QMainWindow.__init__(self) - self.screenList = screens + self.screens = screens self.applicationVersion = applicationVersion self.serviceNotSaved = False self.settingsmanager = SettingsManager(screens) @@ -433,7 +432,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.mainDisplay = MainDisplay(self, screens) self.alertForm = AlertForm(self) self.aboutForm = AboutForm(self, applicationVersion) - self.settingsForm = SettingsForm(self.screenList, self, self) + self.settingsForm = SettingsForm(self.screens, self, self) # Set up the path with plugins pluginpath = os.path.split(os.path.abspath(__file__))[0] pluginpath = os.path.abspath( @@ -500,7 +499,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): #RenderManager needs to call ThemeManager and #ThemeManager needs to call RenderManager self.RenderManager = RenderManager(self.ThemeManagerContents, - self.screenList, self.getMonitorNumber()) + self.screens, self.getMonitorNumber()) #Define the media Dock Manager self.mediaDockManager = MediaDockManager(self.MediaToolBox) log.info(u'Load Plugins') @@ -545,7 +544,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if app_version != version: version_text = unicode(self.trUtf8('OpenLP version %s has been updated ' 'to version %s\n\nYou can obtain the latest version from http://openlp.org')) - QtGui.QMessageBox.question(None, + QtGui.QMessageBox.question(self, self.trUtf8('OpenLP Version Updated'), version_text % (app_version, version), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), @@ -558,11 +557,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): monitor number does not exist. """ screen_number = int(self.generalConfig.get_config(u'monitor', 0)) - monitor_exists = False - for screen in self.screenList: - if screen[u'number'] == screen_number: - monitor_exists = True - if not monitor_exists: + if not self.screens.screen_exists(screen_number): screen_number = 0 return screen_number @@ -580,12 +575,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.ServiceManagerContents.onLoadService(True) if str_to_bool(self.generalConfig.get_config(u'screen blank', False)) \ and str_to_bool(self.generalConfig.get_config(u'blank warning', False)): - QtGui.QMessageBox.question(None, + self.LiveController.onBlankDisplay(True) + QtGui.QMessageBox.question(self, self.trUtf8('OpenLP Main Display Blanked'), self.trUtf8('The Main Display has been blanked out'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), QtGui.QMessageBox.Ok) - self.LiveController.blankButton.setChecked(True) def onHelpAboutItemClicked(self): """ @@ -613,7 +608,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ self.settingsForm.exec_() updated_display = self.getMonitorNumber() - if updated_display != self.RenderManager.current_display: + if updated_display != self.screens.current_display: + self.screens.set_current_display(updated_display) self.RenderManager.update_display(updated_display) self.mainDisplay.setup(updated_display) self.activateWindow() @@ -623,7 +619,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Hook to close the main window and display windows on exit """ if self.serviceNotSaved: - ret = QtGui.QMessageBox.question(None, + ret = QtGui.QMessageBox.question(self, self.trUtf8('Save Changes to Service?'), self.trUtf8('Your service has changed, do you want to save those changes?'), QtGui.QMessageBox.StandardButtons( @@ -704,4 +700,4 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): def togglePreviewPanel(self): previewBool = self.PreviewController.Panel.isVisible() self.PreviewController.Panel.setVisible(not previewBool) - self.settingsmanager.togglePreviewPanel(not previewBool) \ No newline at end of file + self.settingsmanager.togglePreviewPanel(not previewBool) diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py new file mode 100644 index 000000000..2321c3020 --- /dev/null +++ b/openlp/core/ui/screen.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2010 Raoul Snyman # +# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, # +# Carsten Tinggaard # +# --------------------------------------------------------------------------- # +# 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 logging + +class ScreenList(object): + """ + Wrapper to handle the parameters of the display screen + """ + global log + log = logging.getLogger(u'Screen') + log.info(u'Screen loaded') + + def __init__(self): + self.preview = None + self.current = None + self.screen_list = [] + self.count = 0 + self.current_display = 0 + + def add_screen(self, screen): + if screen[u'primary'] == True: + self.current = screen + self.screen_list.append(screen) + self.count += 1 + + def screen_exists(self, number): + for screen in self.screen_list: + if screen[u'number'] == number: + return True + return False + + def set_current_display(self, number): + if number + 1 > self.count: + self.current = self.screen_list[0] + self.current_display = 0 + else: + self.current = self.screen_list[number] + self.preview = self.current + self.current_display = number + if self.count == 1: + self.preview = self.screen_list[0] + +# if self.screen[u'number'] != screenNumber: +# # We will most probably never actually hit this bit, but just in +# # case the index in the list doesn't match the screen number, we +# # search for it. +# for scrn in self.screens: +# if scrn[u'number'] == screenNumber: +# self.screen = scrn +# break + diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 7e9fca933..44170e616 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -348,7 +348,7 @@ class ServiceManager(QtGui.QWidget): if self.parent.serviceNotSaved and \ str_to_bool(PluginConfig(u'General'). get_config(u'save prompt', u'False')): - ret = QtGui.QMessageBox.question(None, + ret = QtGui.QMessageBox.question(self, self.trUtf8('Save Changes to Service?'), self.trUtf8('Your service is unsaved, do you want to save those ' 'changes before creating a new one ?'), @@ -697,4 +697,4 @@ class ServiceManager(QtGui.QWidget): theme = unicode(self.sender().text()) item, count = self.findServiceItem() self.serviceItems[item][u'service_item'].theme = theme - self.regenerateServiceItems() \ No newline at end of file + self.regenerateServiceItems() diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 59dd857ac..3131c2bfa 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -30,7 +30,8 @@ import os from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon -from openlp.core.lib import OpenLPToolbar, Receiver, str_to_bool, PluginConfig +from openlp.core.lib import OpenLPToolbar, Receiver, str_to_bool, \ +PluginConfig, resize_image class SlideList(QtGui.QTableWidget): """ @@ -163,9 +164,9 @@ class SlideController(QtGui.QWidget): self.Toolbar.addToolbarSeparator(u'Close Separator') self.blankButton = self.Toolbar.addToolbarButton( u'Blank Screen', u':/slides/slide_close.png', - self.trUtf8('Blank Screen'), self.onBlankScreen, True) + self.trUtf8('Blank Screen'), self.onBlankDisplay, True) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'live_slide_blank'), self.onBlankDisplay) + QtCore.SIGNAL(u'live_slide_blank'), self.blankScreen) if not self.isLive: self.Toolbar.addToolbarSeparator(u'Close Separator') self.Toolbar.addToolbarButton( @@ -235,6 +236,9 @@ class SlideController(QtGui.QWidget): self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) Phonon.createPath(self.mediaObject, self.video) Phonon.createPath(self.mediaObject, self.audio) + if not self.isLive: + self.video.setGeometry(QtCore.QRect(0, 0, 300, 225)) + self.video.setVisible(False) self.SlideLayout.insertWidget(0, self.video) # Actual preview screen self.SlidePreview = QtGui.QLabel(self) @@ -246,7 +250,8 @@ class SlideController(QtGui.QWidget): self.SlidePreview.sizePolicy().hasHeightForWidth()) self.SlidePreview.setSizePolicy(sizePolicy) self.SlidePreview.setFixedSize( - QtCore.QSize(self.settingsmanager.slidecontroller_image,self.settingsmanager.slidecontroller_image / 1.3 )) + QtCore.QSize(self.settingsmanager.slidecontroller_image, + self.settingsmanager.slidecontroller_image / 1.3 )) self.SlidePreview.setFrameShape(QtGui.QFrame.Box) self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain) self.SlidePreview.setLineWidth(1) @@ -257,8 +262,6 @@ class SlideController(QtGui.QWidget): # Signals QtCore.QObject.connect(self.PreviewListWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected) - QtCore.QObject.connect(self.PreviewListWidget, - QtCore.SIGNAL(u'activated(QModelIndex)'), self.onSlideSelected) if isLive: QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'update_spin_delay'), self.receiveSpinDelay) @@ -441,7 +444,9 @@ class SlideController(QtGui.QWidget): else: label = QtGui.QLabel() label.setMargin(4) - pixmap = self.parent.RenderManager.resize_image(frame[u'image']) + pixmap = resize_image(frame[u'image'], + self.parent.RenderManager.width, + self.parent.RenderManager.height) label.setScaledContents(True) label.setPixmap(QtGui.QPixmap.fromImage(pixmap)) self.PreviewListWidget.setCellWidget(framenumber, 0, label) @@ -480,18 +485,26 @@ class SlideController(QtGui.QWidget): self.PreviewListWidget.selectRow(0) self.onSlideSelected() - def onBlankDisplay(self): - self.blankButton.setChecked(self.parent.mainDisplay.displayBlank) + def onBlankDisplay(self, force=False): + """ + Handle the blank screen button + """ + if force: + self.blankButton.setChecked(True) + self.blankScreen(self.blankButton.isChecked()) + self.parent.generalConfig.set_config(u'screen blank', + self.blankButton.isChecked()) - def onBlankScreen(self, blanked): + def blankScreen(self, blanked=False): """ - Blank the screen. + Blank the display screen. """ - if not self.serviceItem and self.serviceItem.is_command(): - if blanked: - Receiver.send_message(u'%s_blank'% self.serviceItem.name.lower()) - else: - Receiver.send_message(u'%s_unblank'% self.serviceItem.name.lower()) + if self.serviceItem is not None: + if self.serviceItem.is_command(): + if blanked: + Receiver.send_message(u'%s_blank'% self.serviceItem.name.lower()) + else: + Receiver.send_message(u'%s_unblank'% self.serviceItem.name.lower()) else: self.parent.mainDisplay.blankDisplay(blanked) @@ -531,7 +544,7 @@ class SlideController(QtGui.QWidget): def updatePreview(self): rm = self.parent.RenderManager - if not rm.screen_list[rm.current_display][u'primary']: + if not rm.screens.current[u'primary']: # Grab now, but try again in a couple of seconds if slide change is slow QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) QtCore.QTimer.singleShot(2.5, self.grabMainDisplay) @@ -543,7 +556,7 @@ class SlideController(QtGui.QWidget): def grabMainDisplay(self): rm = self.parent.RenderManager winid = QtGui.QApplication.desktop().winId() - rect = rm.screen_list[rm.current_display][u'size'] + rect = rm.screens.current[u'size'] winimg = QtGui.QPixmap.grabWindow(winid, rect.x(), rect.y(), rect.width(), rect.height()) self.SlidePreview.setPixmap(winimg) @@ -635,7 +648,7 @@ class SlideController(QtGui.QWidget): if self.isLive: Receiver.send_message(u'%s_start' % item.name.lower(), \ [item.title, item.service_item_path, - item.get_frame_title(), slideno, self.isLive]) + item.get_frame_title(), self.isLive]) else: self.mediaObject.stop() self.mediaObject.clearQueue() @@ -659,9 +672,9 @@ class SlideController(QtGui.QWidget): def onMediaStop(self): if self.isLive: - Receiver.send_message(u'%s_stop'% self.serviceItem.name.lower()) + Receiver.send_message(u'%s_stop'% self.serviceItem.name.lower(), self.isLive) else: self.mediaObject.stop() self.video.hide() - self.SlidePreview.clear() - self.SlidePreview.show() \ No newline at end of file + self.SlidePreview.clear() + self.SlidePreview.show() diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index fd0284412..0bf005891 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -108,6 +108,8 @@ class ThemeManager(QtGui.QWidget): self.themelist = [] self.path = os.path.join(ConfigHelper.get_data_path(), u'themes') self.checkThemesExists(self.path) + self.thumbPath = os.path.join(self.path, u'.thumbnails') + self.checkThemesExists(self.thumbPath) self.amendThemeForm.path = self.path # Last little bits of setting up self.config = PluginConfig(u'themes') @@ -185,6 +187,7 @@ class ThemeManager(QtGui.QWidget): self.ThemeListWidget.takeItem(row) try: os.remove(os.path.join(self.path, th)) + os.remove(os.path.join(self.thumbPath, th)) shutil.rmtree(os.path.join(self.path, theme)) except: #if not present do not worry @@ -246,25 +249,33 @@ class ThemeManager(QtGui.QWidget): log.debug(u'Load themes from dir') self.themelist = [] self.ThemeListWidget.clear() - for root, dirs, files in os.walk(self.path): - for name in files: - if name.endswith(u'.png'): - #check to see file is in theme root directory - theme = os.path.join(self.path, name) - if os.path.exists(theme): - (path, filename) = os.path.split(unicode(file)) - textName = os.path.splitext(name)[0] - if textName == self.global_theme: - name = u'%s (%s)' % (textName, - self.trUtf8('default')) - else: - name = textName - item_name = QtGui.QListWidgetItem(name) - item_name.setIcon(build_icon(theme)) - item_name.setData(QtCore.Qt.UserRole, - QtCore.QVariant(textName)) - self.ThemeListWidget.addItem(item_name) - self.themelist.append(textName) + #root, dirs, files = os.walk(self.path) + dirList = os.listdir(self.path) + for name in dirList: + if name.endswith(u'.png'): + #check to see file is in theme root directory + theme = os.path.join(self.path, name) + if os.path.exists(theme): + (path, filename) = os.path.split(unicode(file)) + textName = os.path.splitext(name)[0] + if textName == self.global_theme: + name = u'%s (%s)' % (textName, + self.trUtf8('default')) + else: + name = textName + thumb = os.path.join(self.thumbPath, u'%s.png' % textName) + item_name = QtGui.QListWidgetItem(name) + if os.path.exists(thumb): + icon = build_icon(thumb) + else: + icon = build_icon(theme) + pixmap = icon.pixmap(QtCore.QSize(88,50)) + pixmap.save(thumb, u'png') + item_name.setIcon(icon) + item_name.setData(QtCore.Qt.UserRole, + QtCore.QVariant(textName)) + self.ThemeListWidget.addItem(item_name) + self.themelist.append(textName) self.pushThemes() def pushThemes(self): @@ -427,8 +438,6 @@ class ThemeManager(QtGui.QWidget): if outfile: outfile.close() if image_from and image_from != image_to: - print "if", image_from - print "it", image_to try: shutil.copyfile(image_from, image_to) except: @@ -448,6 +457,10 @@ class ThemeManager(QtGui.QWidget): if os.path.exists(samplepathname): os.unlink(samplepathname) frame.save(samplepathname, u'png') + thumb = os.path.join(self.thumbPath, u'%s.png' % name) + icon = build_icon(frame) + pixmap = icon.pixmap(QtCore.QSize(88,50)) + pixmap.save(thumb, u'png') log.debug(u'Theme image written to %s', samplepathname) def generateImage(self, themedata): @@ -529,4 +542,4 @@ class ThemeManager(QtGui.QWidget): theme.font_main_y = int(theme.font_main_y.strip()) #theme.theme_mode theme.theme_name = theme.theme_name.strip() - #theme.theme_version \ No newline at end of file + #theme.theme_version diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index bd8833105..5c9610bf6 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -207,6 +207,7 @@ class HTTPBible(BibleDB): [(u'Genesis', 1, 1, 1), (u'Genesis', 2, 2, 3)] """ + Receiver.send_message(u'bible_showprogress') for reference in reference_list: log.debug('Reference: %s', reference) book = reference[0] @@ -228,6 +229,7 @@ class HTTPBible(BibleDB): db_book = self.get_book(bookname) self.create_chapter(db_book.id, search_results.get_chapter(), search_results.get_verselist()) + Receiver.send_message(u'bible_hideprogress') return BibleDB.get_verses(self, reference_list) def get_chapter(self, version, book, chapter): diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 49cede58a..9f9840fef 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -247,7 +247,9 @@ class BibleMediaItem(MediaManagerItem): QtCore.SIGNAL(u'config_updated'), self.configUpdated) # Other stuff QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'')) + QtCore.SIGNAL(u'bible_showprogress'), self.onSearchProgressShow) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'bible_hideprogress'), self.onSearchProgressHide) def addListViewToToolBar(self): MediaManagerItem.addListViewToToolBar(self) @@ -341,13 +343,13 @@ class BibleMediaItem(MediaManagerItem): (self.ListView.geometry().y() + self.ListView.geometry().height())\ - 23, 81, 23) - def onSearchProgressShow(self, value): + def onSearchProgressShow(self): self.SearchProgress.setVisible(True) - self.SearchProgress.setValue(value) + self.SearchProgress.setMinimum(0) + self.SearchProgress.setMaximum(0) - def onSearchProgressHide(self, value): - self.SearchProgress.setVisible(True) - self.SearchProgress.setValue(value) + def onSearchProgressHide(self): + self.SearchProgress.setVisible(False) def onAdvancedVersionComboBox(self): self.initialiseBible( diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 9ee3a0c6f..8ea1df64b 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -172,7 +172,6 @@ class ImageMediaItem(MediaManagerItem): filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString()) self.OverrideLabel.setText(bitem.text()) frame = QtGui.QImage(unicode(filename)) - self.parent.render_manager.override_background = frame - self.parent.render_manager.override_background_changed = True + self.parent.live_controller.parent.mainDisplay.addImageWithText(frame) else: - MediaManagerItem.onPreviewClick(self) \ No newline at end of file + MediaManagerItem.onPreviewClick(self) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index f9b9f7929..c2dbc5d93 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -61,8 +61,9 @@ class MediaMediaItem(MediaManagerItem): def retranslateUi(self): self.OnNewPrompt = self.trUtf8('Select Media') - self.OnNewFileMasks = self.trUtf8('Videos (*.avi *.mpeg *.mpg' - '*.mp4);;Audio (*.ogg *.mp3 *.wma);;All files (*)') + self.OnNewFileMasks = self.trUtf8('Videos (*.avi *.mpeg *.mpg *.wmv ' + '*.mov *.mp4 *.flv);;Audio (*.ogg *.mp3 *.wma *.wav *.flac)' + ';;All files (*)') def requiredIcons(self): MediaManagerItem.requiredIcons(self) @@ -84,7 +85,7 @@ class MediaMediaItem(MediaManagerItem): for item in items: bitem = self.ListView.item(item.row()) filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString()) - frame = u':/media/media_video.png' + frame = u':/media/image_clapperboard.png' (path, name) = os.path.split(filename) service_item.add_from_command(path, name, frame) return True @@ -110,4 +111,4 @@ class MediaMediaItem(MediaManagerItem): img = self.video_get_preview() item_name.setIcon(build_icon(img)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) - self.ListView.addItem(item_name) \ No newline at end of file + self.ListView.addItem(item_name) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index cd8db7e08..d2a31e202 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -145,7 +145,7 @@ class ImpressController(PresentationController): log.exception(u'Failed to load presentation') return self.presentation = self.document.getPresentation() - self.presentation.Display = self.plugin.render_manager.current_display + 1 + self.presentation.Display = self.plugin.render_manager.screens.current_display + 1 self.controller = None self.create_thumbnails() @@ -169,8 +169,12 @@ class ImpressController(PresentationController): for idx in range(pages.getCount()): page = pages.getByIndex(idx) doc.getCurrentController().setCurrentPage(page) - doc.storeToURL(thumbdir + u'/' + self.thumbnailprefix + - unicode(idx+1) + u'.png', props) + path = u'%s/%s%s.png'% (thumbdir, self.thumbnailprefix, + unicode(idx+1)) + try: + doc.storeToURL(path , props) + except: + log.exception(u'%s\nUnable to store preview' % path) def create_property(self, name, value): if os.name == u'nt': @@ -228,9 +232,13 @@ class ImpressController(PresentationController): """ if self.document: if self.presentation: - self.presentation.end() - self.presentation = None - self.document.dispose() + try: + self.presentation.end() + self.presentation = None + self.document.dispose() + except: + #We tried! + pass self.document = None def is_loaded(self): @@ -248,7 +256,7 @@ class ImpressController(PresentationController): return False if self.controller is None: return False - return self.controller.isRunning() and self.controller.isActive() + return True def unblank_screen(self): return self.controller.resume() @@ -305,4 +313,4 @@ class ImpressController(PresentationController): if os.path.isfile(path): return path else: - return None \ No newline at end of file + return None diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 8094b804e..0b2fd6003 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -47,7 +47,7 @@ class Controller(object): log.debug(u'Live = %s, addHandler %s' % (self.isLive, file)) self.controller = controller if self.controller.is_loaded(): - self.shutdown(None) + self.shutdown() self.controller.load_presentation(file) if self.isLive: self.controller.start_presentation() @@ -73,55 +73,51 @@ class Controller(object): self.controller.goto_slide(int(slide) + 1) self.controller.poll_slidenumber(live) - def first(self, message): + def first(self): """ Based on the handler passed at startup triggers the first slide """ log.debug(u'Live = %s, first' % self.isLive) - print "first ", message if not self.isLive: return self.activate() self.controller.start_presentation() self.controller.poll_slidenumber(self.isLive) - def last(self, message): + def last(self): """ Based on the handler passed at startup triggers the first slide """ log.debug(u'Live = %s, last' % self.isLive) - print "last ", message if not self.isLive: return self.activate() self.controller.goto_slide(self.controller.get_slide_count()) self.controller.poll_slidenumber(self.isLive) - def next(self, message): + def next(self): """ Based on the handler passed at startup triggers the next slide event """ log.debug(u'Live = %s, next' % self.isLive) - print "next ", message if not self.isLive: return self.activate() self.controller.next_step() self.controller.poll_slidenumber(self.isLive) - def previous(self, message): + def previous(self): """ Based on the handler passed at startup triggers the previous slide event """ log.debug(u'Live = %s, previous' % self.isLive) if not self.isLive: return - print "previous ", message self.activate() self.controller.previous_step() self.controller.poll_slidenumber(self.isLive) - def shutdown(self, message): + def shutdown(self): """ Based on the handler passed at startup triggers slide show to shut down """ @@ -159,7 +155,6 @@ class MessageListener(object): self.controllers = controllers self.previewHandler = Controller(False) self.liveHandler = Controller(True) - self.isLive = None # messages are sent from core.ui.slidecontroller QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'presentations_start'), self.startup) @@ -202,36 +197,36 @@ class MessageListener(object): else: self.previewHandler.slide(slide, live) - def first(self, message): - if self.isLive: - self.liveHandler.first(message) + def first(self, isLive): + if isLive: + self.liveHandler.first() else: - self.previewHandler.first(message) + self.previewHandler.first() - def last(self, message): - if self.isLive: - self.liveHandler.last(message) + def last(self, isLive): + if isLive: + self.liveHandler.last() else: - self.previewHandler.last(message) + self.previewHandler.last() - def next(self, message): - if self.isLive: - self.liveHandler.next(message) + def next(self, isLive): + if isLive: + self.liveHandler.next() else: - self.previewHandler.next(message) + self.previewHandler.next() - def previous(self, message): - if self.isLive: - self.liveHandler.previous(message) + def previous(self, isLive): + if isLive: + self.liveHandler.previous() else: - self.previewHandler.previous(message) + self.previewHandler.previous() - def shutdown(self, message): - if self.isLive: - self.liveHandler.shutdown(message) + def shutdown(self, isLive): + if isLive: + self.liveHandler.shutdown() Receiver.send_message(u'live_slide_show') else: - self.previewHandler.shutdown(message) + self.previewHandler.shutdown() def blank(self): if self.isLive: @@ -268,4 +263,4 @@ class MessageListener(object): return message[0], file, message[4] def timeout(self): - self.controller.poll_slidenumber(self.is_live) \ No newline at end of file + self.controller.poll_slidenumber(self.is_live) diff --git a/openlp/plugins/songusage/forms/songusagedeleteform.py b/openlp/plugins/songusage/forms/songusagedeleteform.py index b20f13c6b..98faf26ad 100644 --- a/openlp/plugins/songusage/forms/songusagedeleteform.py +++ b/openlp/plugins/songusage/forms/songusagedeleteform.py @@ -33,11 +33,11 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog): """ Class documentation goes here. """ - def __init__(self, auditmanager, parent=None): + def __init__(self, songusagemanager, parent=None): """ Constructor """ - self.auditmanager = auditmanager + self.songusagemanager = songusagemanager QtGui.QDialog.__init__(self, parent) self.setupUi(self) @@ -52,5 +52,5 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog): if ret == QtGui.QMessageBox.Ok: qDeleteDate = self.DeleteCalendar.selectedDate() deleteDate = date(qDeleteDate.year(), qDeleteDate.month(), qDeleteDate.day()) - self.auditmanager.delete_to_date(deleteDate) - self.close() \ No newline at end of file + self.songusagemanager.delete_to_date(deleteDate) + self.close() diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 93b6d2e98..ead6b5166 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -25,10 +25,14 @@ import os from PyQt4 import QtCore, QtGui +import logging from songusagedetaildialog import Ui_SongUsageDetailDialog class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog): + global log + log = logging.getLogger(u'SongUsageDetailForm') + log.info(u'SongUsage Detail Form loaded') """ Class documentation goes here. """ @@ -106,19 +110,19 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog): self.close() def detailedReport(self): - print "detailed" - filename = u'audit_det_%s_%s.txt' % \ + log.debug(u'Detailed report generated') + filename = u'usage_detail_%s_%s.txt' % \ (self.FromDateEdit.date().toString(u'ddMMyyyy'), self.ToDateEdit.date().toString(u'ddMMyyyy')) - audits = self.parent.auditmanager.get_all_audits() + usage = self.parent.songusagemanager.get_all_songusage() outname = os.path.join(unicode(self.FileLineEdit.text()), filename) file = None try: file = open(outname, u'w') - for audit in audits: + for instance in usage: record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n' % \ - (audit.auditdate,audit.audittime, audit.title, - audit.copyright, audit.ccl_number , audit.authors) + (instance.usagedate,instance.usagetime, instance.title, + instance.copyright, instance.ccl_number , instance.authors) file.write(record) except: log.exception(u'Failed to write out audit records') @@ -127,8 +131,7 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog): file.close() def summaryReport(self): - print "summary" + log.debug(u'Summary report generated') filename = u'audit_sum_%s_%s.txt' % \ (self.FromDateEdit.date().toString(u'ddMMyyyy'), self.ToDateEdit.date().toString(u'ddMMyyyy')) - print filename \ No newline at end of file diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index effc06657..802f73d3d 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -141,7 +141,7 @@ class SongUsagePlugin(Plugin): SongUsageitem.authors = u'' for author in SongUsageData[1]: SongUsageitem.authors += author + u' ' - self.songusagemanager.insert_SongUsage(SongUsageitem) + self.songusagemanager.insert_songusage(SongUsageitem) def onSongUsageDelete(self): self.SongUsagedeleteform.exec_() @@ -154,4 +154,4 @@ class SongUsagePlugin(Plugin): about_text = self.trUtf8('SongUsage Plugin
This plugin ' 'records the use of songs and when they have been used during ' 'a live service') - return about_text \ No newline at end of file + return about_text diff --git a/resources/images/image_clapperboard.png b/resources/images/image_clapperboard.png new file mode 100644 index 000000000..e46056914 Binary files /dev/null and b/resources/images/image_clapperboard.png differ diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc index 8fa38c42b..4bea9e51b 100644 --- a/resources/images/openlp-2.qrc +++ b/resources/images/openlp-2.qrc @@ -108,6 +108,7 @@ media_video.png media_time.png media_stop.png + image_clapperboard.png messagebox_critical.png diff --git a/scripts/bible-1to2-converter.py b/scripts/bible-1to2-converter.py new file mode 100755 index 000000000..226c1ec2e --- /dev/null +++ b/scripts/bible-1to2-converter.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2010 Raoul Snyman # +# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Maikel Stuivenberg, Martin Thompson, Jon Tibble, # +# Carsten Tinggaard # +# --------------------------------------------------------------------------- # +# 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 sys +import os +import sqlite +import sqlite3 +import re +from optparse import OptionParser +from traceback import format_tb as get_traceback + +# Some global options to be used throughout the import process +verbose = False +debug = False +old_cursor = None +new_cursor = None + +# SQL create statments +create_statements = [ + (u'table "book"', u"""CREATE TABLE book ( + id INTEGER NOT NULL, + testament_id INTEGER, + name VARCHAR(30), + abbreviation VARCHAR(5), + PRIMARY KEY (id), + FOREIGN KEY(testament_id) REFERENCES testament (id) +)"""), + (u'table "metadata"', u"""CREATE TABLE metadata ( + "key" VARCHAR(255) NOT NULL, + value VARCHAR(255), + PRIMARY KEY ("key") +)"""), + (u'table "testament"', u"""CREATE TABLE testament ( + id INTEGER NOT NULL, + name VARCHAR(30), + PRIMARY KEY (id) +)"""), + (u'table "verse"', u"""CREATE TABLE verse ( + id INTEGER NOT NULL, + book_id INTEGER, + chapter INTEGER, + verse INTEGER, + text TEXT, + PRIMARY KEY (id), + FOREIGN KEY(book_id) REFERENCES book (id) +)"""), + (u'index "idx_abbrev"', + u"""CREATE INDEX idx_abbrev ON book (abbreviation, id)"""), + (u'index "idx_chapter_verse_book', + u"""CREATE INDEX idx_chapter_verse_book ON verse (chapter, verse, book_id, id)"""), + (u'index "idx_chapter_verse_text"', + u"""CREATE INDEX idx_chapter_verse_text ON verse (text, verse, book_id, id)"""), + (u'index "idx_name"', + u"""CREATE INDEX idx_name ON book (name, id)""") +] + +def display_sql(sql, params): + prepared_params = [] + for param in params: + if isinstance(param, basestring): + prepared_params.append(u'"%s"' % param) + elif isinstance(param, (int, long)): + prepared_params.append(u'%d' % param) + elif isinstance(param, (float, complex)): + prepared_params.append(u'%f' % param) + else: + prepared_params.append(u'"%s"' % str(param)) + for prepared_param in prepared_params: + sql = sql.replace(u'?', prepared_param, 1) + return sql + +def create_database(): + global new_cursor, create_statements + if debug or verbose: + print 'Creating new database:' + else: + print 'Creating new database...', + for statement_type, sql_create in create_statements: + if debug: + print '... ', sql_create.replace('\n', ' ').replace(' ', ' ') + elif verbose: + print '... creating %s...' % statement_type, + new_cursor.execute(sql_create) + if verbose and not debug: + print 'done.' + if not verbose and not debug: + print 'done.' + +def import_bible(): + global old_cursor, new_cursor, debug, verbose + if debug or verbose: + print 'Importing metadata:' + else: + print 'Importing metadata...', + if debug: + print '... SELECT "key", "value" FROM metadata' + elif verbose: + print '... fetching metadata from old database...', + old_cursor.execute(u'SELECT "key", "value" FROM metadata') + rows = old_cursor.fetchall() + if not debug and verbose: + print 'done.' + for row in rows: + key = unicode(row[0], u'cp1252') + value = unicode(row[1], u'cp1252') + sql_insert = u'INSERT INTO metadata '\ + '("key", "value") '\ + 'VALUES (?, ?)' + sql_params = (key, value) + if debug: + print '...', display_sql(sql_insert, sql_params) + elif verbose: + print '... importing "%s"' % key + new_cursor.execute(sql_insert, sql_params) + if not verbose and not debug: + print 'done.' + if debug or verbose: + print 'Importing testaments:' + else: + print 'Importing testaments...', + if debug: + print '... SELECT id, name FROM testament' + elif verbose: + print '... fetching testaments from old database...', + old_cursor.execute(u'SELECT id, name FROM testament') + rows = old_cursor.fetchall() + if not debug and verbose: + print 'done.' + for row in rows: + id = int(row[0]) + name = unicode(row[1], u'cp1252') + sql_insert = u'INSERT INTO testament '\ + '(id, name) '\ + 'VALUES (?, ?)' + sql_params = (id, name) + if debug: + print '...', display_sql(sql_insert, sql_params) + elif verbose: + print '... importing "%s"' % name + new_cursor.execute(sql_insert, sql_params) + if not verbose and not debug: + print 'done.' + if debug or verbose: + print 'Importing books:' + else: + print 'Importing books...', + if debug: + print '... SELECT id, testament_id, name, abbreviation FROM book' + elif verbose: + print '... fetching books from old database...', + old_cursor.execute(u'SELECT id, testament_id, name, abbreviation FROM book') + rows = old_cursor.fetchall() + if not debug and verbose: + print 'done.' + book_map = {} + for row in rows: + testament_id = int(row[1]) + name = unicode(row[2], u'cp1252') + abbreviation = unicode(row[3], u'cp1252') + sql_insert = u'INSERT INTO book '\ + '(id, testament_id, name, abbreviation) '\ + 'VALUES (NULL, ?, ?, ?)' + sql_params = (testament_id, name, abbreviation) + if debug: + print '...', display_sql(sql_insert, sql_params) + elif verbose: + print '... importing "%s"' % name + new_cursor.execute(sql_insert, sql_params) + book_map[row[0]] = new_cursor.lastrowid + if debug: + print ' >>> (old) books.id =', row[0], ' (new) books.id =', book_map[row[0]] + if not verbose and not debug: + print 'done.' + if debug or verbose: + print 'Importing verses:' + else: + print 'Importing verses...', + if debug: + print '... SELECT id, book_id, chapter, verse, text || \'\' AS text FROM verse...', + elif verbose: + print '... fetching verses from old database...', + old_cursor.execute(u'SELECT id, book_id, chapter, verse, text || \'\' AS text FROM verse') + rows = old_cursor.fetchall() + if debug or verbose: + print 'done.' + song_map = {} + for row in rows: + book_id = int(row[1]) + chapter = int(row[2]) + verse = int(row[3]) + text = unicode(row[4], u'cp1252') + sql_insert = u'INSERT INTO verse '\ + '(id, book_id, chapter, verse, text) '\ + 'VALUES (NULL, ?, ?, ?, ?)' + sql_params = (book_map[book_id], chapter, verse, text) + if debug: + print '...', display_sql(sql_insert, sql_params) + elif verbose: + print '... importing "%s..."' % text[:17] + new_cursor.execute(sql_insert, sql_params) + if not verbose and not debug: + print 'done.' + +def main(old_db, new_db): + global old_cursor, new_cursor, debug + old_connection = None + new_connection = None + try: + old_connection = sqlite.connect(old_db) + except: + if debug: + errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\ + + str(sys.exc_info()[1]) + else: + errormsg = sys.exc_info()[1] + print 'There was a problem connecting to the old database:', errormsg + return 1 + try: + new_connection = sqlite3.connect(new_db) + except: + if debug: + errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\ + + str(sys.exc_info()[1]) + else: + errormsg = sys.exc_info()[1] + print 'There was a problem creating the new database:', errormsg + return 1 + old_cursor = old_connection.cursor() + new_cursor = new_connection.cursor() + try: + create_database() + except: + if debug: + errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\ + + str(sys.exc_info()[1]) + else: + errormsg = sys.exc_info()[1] + print 'There was a problem creating the database:', errormsg + return 1 + try: + import_bible() + new_connection.commit() + except: + new_connection.rollback() + if debug: + errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\ + + str(sys.exc_info()[1]) + else: + errormsg = sys.exc_info()[1] + print 'There was a problem importing songs:', errormsg + return 1 + print 'Import complete.' + +if __name__ == u'__main__': + option_parser = OptionParser(usage='Usage: %prog [options] OLDDATABASE NEWDATABASE') + option_parser.add_option('-o', '--overwrite', dest='overwrite', default=False, + action=u'store_true', help='Overwrite database file if it already exists.') + option_parser.add_option('-v', '--verbose', dest='verbose', default=False, + action=u'store_true', help='Outputs additional progress data.') + option_parser.add_option('-d', '--debug', dest='debug', default=False, + action=u'store_true', help='Outputs raw SQL statements (overrides verbose).') + options, arguments = option_parser.parse_args() + if len(arguments) < 2: + if len(arguments) == 0: + option_parser.error('Please specify an old database and a new database.') + else: + option_parser.error('Please specify a new database.') + old_db = os.path.abspath(arguments[0]) + new_db = os.path.abspath(arguments[1]) + if not os.path.isfile(old_db): + option_parser.error('Old database file ("%s") is not a file.' % old_db) + if not os.path.exists(old_db): + option_parser.error('Old database file ("%s") does not exist.' % old_db) + if os.path.exists(new_db): + if not options.overwrite: + option_parser.error('New database file ("%s") exists. If you want to overwrite it, specify the --overwrite option.' % new_db) + else: + if not os.path.isfile(new_db): + option_parser.error('New database file ("%s") is not a file.' % new_db) + os.unlink(new_db) + verbose = options.verbose + debug = options.debug + main(old_db, new_db) diff --git a/version.txt b/version.txt index fbb45f3be..d490f5631 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.9.0-694 +1.9.0-698