← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~googol/openlp/render into lp:openlp

 

Andreas Preikschat has proposed merging lp:~googol/openlp/render into lp:openlp.

Requested reviews:
  Tim Bentley (trb143)
  Andreas Preikschat (googol)

For more details, see:
https://code.launchpad.net/~googol/openlp/render/+merge/107264

Reworked some renderer code.

This improves the performance a bit. And improves code readability/clearness (at least that what I think). :-D

branch: http://pastebin.com/qyZ9WYNz
trunk: http://pastebin.com/tgMHv8D0

I tested
- the setup with all different theme levels. 
- editing (is the edited theme used instead the old version?)
- changing screen setup
-- 
https://code.launchpad.net/~googol/openlp/render/+merge/107264
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2012-05-20 20:56:11 +0000
+++ openlp/core/lib/renderer.py	2012-05-24 19:11:19 +0000
@@ -59,25 +59,28 @@
         """
         Initialise the renderer.
 
-    ``imageManager``
-        A imageManager instance which takes care of e. g. caching and resizing
-        images.
+        ``imageManager``
+            A imageManager instance which takes care of e. g. caching and
+            resizing images.
 
-    ``themeManager``
-        The themeManager instance, used to get the current theme details.
+        ``themeManager``
+            The themeManager instance, used to get the current theme details.
         """
         log.debug(u'Initialisation started')
         self.themeManager = themeManager
         self.imageManager = imageManager
         self.screens = ScreenList()
-        self.service_theme = u''
-        self.theme_level = u''
-        self.override_background = None
-        self.theme_data = None
-        self.bg_frame = None
+        self.theme_level = ThemeLevel.Global
+        self.service_theme_name = u''
+        self.service_theme_name = u''
+        self.item_theme_name = u''
         self.force_page = False
         self.display = MainDisplay(None, self.imageManager, False, self)
         self.display.setup()
+        self._theme_dimensions = {}
+        self._calculate_default()
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'theme_update_global'), self.set_global_theme)
 
     def update_display(self):
         """
@@ -89,86 +92,130 @@
             self.display.close()
         self.display = MainDisplay(None, self.imageManager, False, self)
         self.display.setup()
-        self.bg_frame = None
-        self.theme_data = None
-
-    def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
-        """
-        Set the global-level theme and the theme level.
-
-        ``global_theme``
-            The global-level theme to be set.
+        self._theme_dimensions = {}
+
+    def update_theme(self, theme_name, old_theme_name=None, only_delete=False):
+        """
+        This method updates the theme in ``_theme_dimensions`` when a theme
+        has been edited or renamed.
+
+        ``theme_name``
+            The current theme name.
+
+        ``old_theme_name``
+            The old theme name. Has only to be passed, when the theme has been
+            renamed. Defaults to *None*.
+
+        ``only_delete``
+            Only remove the given ``theme_name`` from the ``_theme_dimensions``
+            list. This can be used when a theme is permanently deleted.
+        """
+        if old_theme_name is not None and \
+            old_theme_name in self._theme_dimensions:
+            del self._theme_dimensions[old_theme_name]
+        if theme_name in self._theme_dimensions:
+            del self._theme_dimensions[theme_name]
+        if not only_delete:
+            self._set_theme(theme_name)
+
+    def _set_theme(self, theme_name):
+        """
+        Helper method to save theme names and theme data.
+
+        ``theme_name``
+            The theme name.
+        """
+        if theme_name not in self._theme_dimensions:
+            theme_data = self.themeManager.getThemeData(theme_name)
+            main_rect = self.get_main_rectangle(theme_data)
+            footer_rect = self.get_footer_rectangle(theme_data)
+            self._theme_dimensions[theme_name] = \
+                [theme_data, main_rect, footer_rect]
+        else:
+            theme_data, main_rect, footer_rect = \
+                self._theme_dimensions[theme_name]
+        # if No file do not update cache
+        if theme_data.background_filename:
+            self.imageManager.add_image(theme_data.theme_name,
+                theme_data.background_filename, u'theme',
+                QtGui.QColor(theme_data.background_border_color))
+
+    def pre_render(self, override_theme_data=None):
+        """
+        Set up the theme to be used before rendering an item.
+
+        ``override_theme_data``
+            The theme data should be passed, when we want to use our own theme
+            data, regardless of the theme level. This should for example be used
+            in the theme manager. **Note**, this is **not** to be mixed up with
+            the ``set_item_theme`` method.
+        """
+        # Just assume we use the global theme.
+        theme_to_use = self.global_theme_name
+        # The theme level is either set to Service or Item. Use the service
+        # theme if one is set. We also have to use the service theme, even when
+        # the theme level is set to Item, because the item does not necessarily
+        # have to have a theme.
+        if self.theme_level != ThemeLevel.Global:
+            # When the theme level is at Service and we actually have a service
+            # theme then use it.
+            if self.service_theme_name:
+                theme_to_use = self.service_theme_name
+        # If we have Item level and have an item theme then use it.
+        if self.theme_level == ThemeLevel.Song and self.item_theme_name:
+            theme_to_use = self.item_theme_name
+        if override_theme_data is None:
+            if theme_to_use not in self._theme_dimensions:
+                self._set_theme(theme_to_use)
+            theme_data, main_rect, footer_rect = \
+                self._theme_dimensions[theme_to_use]
+        else:
+            # Ignore everything and use own theme data.
+            theme_data = override_theme_data
+            main_rect = self.get_main_rectangle(override_theme_data)
+            footer_rect = self.get_footer_rectangle(override_theme_data)
+        self._set_text_rectangle(theme_data, main_rect, footer_rect)
+        return theme_data, self._rect, self._rect_footer
+
+    def set_theme_level(self, theme_level):
+        """
+        Sets the theme level.
 
         ``theme_level``
-            Defaults to ``ThemeLevel.Global``. The theme level, can be
-            ``ThemeLevel.Global``, ``ThemeLevel.Service`` or
-            ``ThemeLevel.Song``.
+            The theme level to be used.
         """
-        self.global_theme = global_theme
         self.theme_level = theme_level
-        self.global_theme_data = \
-            self.themeManager.getThemeData(self.global_theme)
-        self.theme_data = None
-
-    def set_service_theme(self, service_theme):
+
+    def set_global_theme(self, global_theme_name):
+        """
+        Set the global-level theme name.
+
+        ``global_theme_name``
+            The global-level theme's name.
+        """
+        self._set_theme(global_theme_name)
+        self.global_theme_name = global_theme_name
+
+    def set_service_theme(self, service_theme_name):
         """
         Set the service-level theme.
 
-        ``service_theme``
-            The service-level theme to be set.
-        """
-        self.service_theme = service_theme
-        self.theme_data = None
-
-    def set_override_theme(self, override_theme, override_levels=False):
-        """
-        Set the appropriate theme depending on the theme level.
-        Called by the service item when building a display frame
-
-        ``override_theme``
-            The name of the song-level theme. None means the service
-            item wants to use the given value.
-
-        ``override_levels``
-            Used to force the theme data passed in to be used.
-        """
-        log.debug(u'set override theme to %s', override_theme)
-        theme_level = self.theme_level
-        if override_levels:
-            theme_level = ThemeLevel.Song
-        if theme_level == ThemeLevel.Global:
-            theme = self.global_theme
-        elif theme_level == ThemeLevel.Service:
-            if self.service_theme == u'':
-                theme = self.global_theme
-            else:
-                theme = self.service_theme
-        else:
-            # Images have a theme of -1
-            if override_theme and override_theme != -1:
-                theme = override_theme
-            elif theme_level == ThemeLevel.Song or \
-                theme_level == ThemeLevel.Service:
-                if self.service_theme == u'':
-                    theme = self.global_theme
-                else:
-                    theme = self.service_theme
-            else:
-                theme = self.global_theme
-        log.debug(u'theme is now %s', theme)
-        # Force the theme to be the one passed in.
-        if override_levels:
-            self.theme_data = override_theme
-        else:
-            self.theme_data = self.themeManager.getThemeData(theme)
-        self._calculate_default()
-        self._build_text_rectangle(self.theme_data)
-        # if No file do not update cache
-        if self.theme_data.background_filename:
-            self.imageManager.add_image(self.theme_data.theme_name,
-                self.theme_data.background_filename, u'theme',
-                QtGui.QColor(self.theme_data.background_border_color))
-        return self._rect, self._rect_footer
+        ``service_theme_name``
+            The service level theme's name.
+        """
+        self._set_theme(service_theme_name)
+        self.service_theme_name = service_theme_name
+
+    def set_item_theme(self, item_theme_name):
+        """
+        Set the item-level theme. **Note**, this has to be done for each item we
+        are rendering.
+
+        ``item_theme_name``
+            The item theme's name.
+        """
+        self._set_theme(item_theme_name)
+        self.item_theme_name = item_theme_name
 
     def generate_preview(self, theme_data, force_page=False):
         """
@@ -183,11 +230,8 @@
         log.debug(u'generate preview')
         # save value for use in format_slide
         self.force_page = force_page
-        # set the default image size for previews
-        self._calculate_default()
         # build a service item to generate preview
         serviceItem = ServiceItem()
-        serviceItem.theme = theme_data
         if self.force_page:
             # make big page for theme edit dialog to get line count
             serviceItem.add_from_text(u'', VERSE_FOR_LINE_COUNT)
@@ -196,14 +240,21 @@
             serviceItem.add_from_text(u'', VERSE)
         serviceItem.renderer = self
         serviceItem.raw_footer = FOOTER
+        # if No file do not update cache
+        if theme_data.background_filename:
+            self.imageManager.add_image(theme_data.theme_name,
+                theme_data.background_filename, u'theme',
+                QtGui.QColor(theme_data.background_border_color))
+        theme_data, main, footer = self.pre_render(theme_data)
+        serviceItem.themedata = theme_data
+        serviceItem.main = main
+        serviceItem.footer = footer
         serviceItem.render(True)
         if not self.force_page:
             self.display.buildHtml(serviceItem)
             raw_html = serviceItem.get_rendered_frame(0)
             self.display.text(raw_html)
             preview = self.display.preview()
-            # Reset the real screen size for subsequent render requests
-            self._calculate_default()
             return preview
         self.force_page = False
 
@@ -303,52 +354,41 @@
         # 90% is start of footer
         self.footer_start = int(self.height * 0.90)
 
-    def _build_text_rectangle(self, theme):
-        """
-        Builds a text block using the settings in ``theme``
-        and the size of the display screen.height.
-        Note the system has a 10 pixel border round the screen
-
-        ``theme``
-            The theme to build a text block for.
-        """
-        log.debug(u'_build_text_rectangle')
-        main_rect = self.get_main_rectangle(theme)
-        footer_rect = self.get_footer_rectangle(theme)
-        self._set_text_rectangle(main_rect, footer_rect)
-
-    def get_main_rectangle(self, theme):
+    def get_main_rectangle(self, theme_data):
         """
         Calculates the placement and size of the main rectangle.
 
-        ``theme``
+        ``theme_data``
             The theme information
         """
-        if not theme.font_main_override:
-            return QtCore.QRect(10, 0, self.width - 20, self.footer_start)
+        if not theme_data.font_main_override:
+            return QtCore.QRect(10, 0, self.width, self.footer_start)
         else:
-            return QtCore.QRect(theme.font_main_x, theme.font_main_y,
-                theme.font_main_width - 1, theme.font_main_height - 1)
+            return QtCore.QRect(theme_data.font_main_x, theme_data.font_main_y,
+                theme_data.font_main_width - 1, theme_data.font_main_height - 1)
 
-    def get_footer_rectangle(self, theme):
+    def get_footer_rectangle(self, theme_data):
         """
         Calculates the placement and size of the footer rectangle.
 
-        ``theme``
-            The theme information
+        ``theme_data``
+            The theme data.
         """
-        if not theme.font_footer_override:
+        if not theme_data.font_footer_override:
             return QtCore.QRect(10, self.footer_start, self.width - 20,
                 self.height - self.footer_start)
         else:
-            return QtCore.QRect(theme.font_footer_x,
-                theme.font_footer_y, theme.font_footer_width - 1,
-                theme.font_footer_height - 1)
+            return QtCore.QRect(theme_data.font_footer_x,
+                theme_data.font_footer_y, theme_data.font_footer_width - 1,
+                theme_data.font_footer_height - 1)
 
-    def _set_text_rectangle(self, rect_main, rect_footer):
+    def _set_text_rectangle(self, theme_data, rect_main, rect_footer):
         """
         Sets the rectangle within which text should be rendered.
 
+        ``theme_data``
+            The theme data.
+
         ``rect_main``
             The main text block.
 
@@ -360,9 +400,9 @@
         self._rect_footer = rect_footer
         self.page_width = self._rect.width()
         self.page_height = self._rect.height()
-        if self.theme_data.font_main_shadow:
-            self.page_width -= int(self.theme_data.font_main_shadow_size)
-            self.page_height -= int(self.theme_data.font_main_shadow_size)
+        if theme_data.font_main_shadow:
+            self.page_width -= int(theme_data.font_main_shadow_size)
+            self.page_height -= int(theme_data.font_main_shadow_size)
         self.web = QtWebKit.QWebView()
         self.web.setVisible(False)
         self.web.resize(self.page_width, self.page_height)
@@ -380,8 +420,8 @@
             </script><style>*{margin: 0; padding: 0; border: 0;}
             #main {position: absolute; top: 0px; %s %s}</style></head><body>
             <div id="main"></div></body></html>""" % \
-            (build_lyrics_format_css(self.theme_data, self.page_width,
-            self.page_height), build_lyrics_outline_css(self.theme_data))
+            (build_lyrics_format_css(theme_data, self.page_width,
+            self.page_height), build_lyrics_outline_css(theme_data))
         self.web.setHtml(html)
         self.empty_height = self.web_frame.contentsSize().height()
 

=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py	2012-05-05 12:24:25 +0000
+++ openlp/core/lib/serviceitem.py	2012-05-24 19:11:19 +0000
@@ -158,19 +158,24 @@
         self.icon = icon
         self.iconic_representation = build_icon(icon)
 
-    def render(self, use_override=False):
+    def render(self, provides_own_theme_data=False):
         """
         The render method is what generates the frames for the screen and
         obtains the display information from the renderer. At this point all
         slides are built for the given display size.
+
+        ``provides_own_theme_data``
+            This switch disables the usage of the item's theme. However, this is
+            disabled by default. If this is used, it has to be taken care, that
+            the renderer knows the correct theme data. However, this is needed
+            for the theme manager.
         """
         log.debug(u'Render called')
         self._display_frames = []
         self.bg_image_bytes = None
-        theme = self.theme if self.theme else None
-        self.main, self.footer = \
-            self.renderer.set_override_theme(theme, use_override)
-        self.themedata = self.renderer.theme_data
+        if not provides_own_theme_data:
+            self.renderer.set_item_theme(self.theme)
+            self.themedata, self.main, self.footer = self.renderer.pre_render()
         if self.service_item_type == ServiceItemType.Text:
             log.debug(u'Formatting slides')
             for slide in self._raw_frames:

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2012-05-20 20:56:11 +0000
+++ openlp/core/ui/slidecontroller.py	2012-05-24 19:11:19 +0000
@@ -863,7 +863,7 @@
                     image = self.imageManager.get_image(frame[u'title'])
                     label.setPixmap(QtGui.QPixmap.fromImage(image))
                 self.previewListWidget.setCellWidget(framenumber, 0, label)
-                slideHeight = width * self.parent().renderer.screen_ratio
+                slideHeight = width * (1 / self.ratio)
                 row += 1
                 self.slideList[unicode(row)] = row - 1
             text.append(unicode(row))

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2012-04-29 15:31:56 +0000
+++ openlp/core/ui/thememanager.py	2012-05-24 19:11:19 +0000
@@ -247,8 +247,7 @@
                 QtCore.QSettings().setValue(
                     self.settingsSection + u'/global theme',
                     QtCore.QVariant(self.global_theme))
-                Receiver.send_message(u'theme_update_global',
-                    self.global_theme)
+                Receiver.send_message(u'theme_update_global', self.global_theme)
                 self._pushThemes()
 
     def onAddTheme(self):
@@ -284,6 +283,8 @@
                         if plugin.usesTheme(old_theme_name):
                             plugin.renameTheme(old_theme_name, new_theme_name)
                     self.loadThemes()
+                    self.mainwindow.renderer.update_theme(
+                        new_theme_name, old_theme_name)
 
     def onCopyTheme(self):
         """
@@ -320,9 +321,8 @@
         Loads the settings for the theme that is to be edited and launches the
         theme editing form so the user can make their changes.
         """
-        if check_item_selected(self.themeListWidget,
-            translate('OpenLP.ThemeManager',
-            'You must select a theme to edit.')):
+        if check_item_selected(self.themeListWidget, translate(
+            'OpenLP.ThemeManager', 'You must select a theme to edit.')):
             item = self.themeListWidget.currentItem()
             theme = self.getThemeData(
                 unicode(item.data(QtCore.Qt.UserRole).toString()))
@@ -331,6 +331,7 @@
             self.themeForm.theme = theme
             self.themeForm.exec_(True)
             self.old_background_image = None
+            self.mainwindow.renderer.update_theme(theme.theme_name)
 
     def onDeleteTheme(self):
         """
@@ -348,6 +349,7 @@
             # As we do not reload the themes, push out the change. Reload the
             # list as the internal lists and events need to be triggered.
             self._pushThemes()
+            self.mainwindow.renderer.update_theme(theme, only_delete=True)
 
     def deleteTheme(self, theme):
         """

=== modified file 'openlp/core/ui/themestab.py'
--- openlp/core/ui/themestab.py	2012-04-22 19:37:11 +0000
+++ openlp/core/ui/themestab.py	2012-05-24 19:11:19 +0000
@@ -151,8 +151,8 @@
         settings.setValue(u'theme level', QtCore.QVariant(self.theme_level))
         settings.setValue(u'global theme', QtCore.QVariant(self.global_theme))
         settings.endGroup()
-        self.mainwindow.renderer.set_global_theme(
-            self.global_theme, self.theme_level)
+        self.mainwindow.renderer.set_global_theme(self.global_theme)
+        self.mainwindow.renderer.set_theme_level(self.theme_level)
         Receiver.send_message(u'theme_update_global', self.global_theme)
 
     def postSetUp(self):
@@ -169,8 +169,8 @@
 
     def onDefaultComboBoxChanged(self, value):
         self.global_theme = unicode(self.DefaultComboBox.currentText())
-        self.mainwindow.renderer.set_global_theme(
-            self.global_theme, self.theme_level)
+        self.mainwindow.renderer.set_global_theme(self.global_theme)
+        self.mainwindow.renderer.set_theme_level(self.theme_level)
         self.__previewGlobalTheme()
 
     def updateThemeList(self, theme_list):
@@ -189,8 +189,8 @@
         self.DefaultComboBox.clear()
         self.DefaultComboBox.addItems(theme_list)
         find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
-        self.mainwindow.renderer.set_global_theme(
-            self.global_theme, self.theme_level)
+        self.mainwindow.renderer.set_global_theme(self.global_theme)
+        self.mainwindow.renderer.set_theme_level(self.theme_level)
         if self.global_theme is not u'':
             self.__previewGlobalTheme()
 

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2012-04-29 15:31:56 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2012-05-24 19:11:19 +0000
@@ -197,9 +197,6 @@
 
     def generateSlideData(self, service_item, item=None, xmlVersion=False,
         remote=False):
-        raw_footer = []
-        slide = None
-        theme = None
         item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
         service_item.add_capability(ItemCapabilities.CanEdit)
         service_item.add_capability(ItemCapabilities.CanPreview)
@@ -207,6 +204,7 @@
         service_item.add_capability(ItemCapabilities.CanSoftBreak)
         customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
         title = customSlide.title
+        service_item.title = title
         credit = customSlide.credits
         service_item.edit_id = item_id
         theme = customSlide.theme_name
@@ -215,15 +213,13 @@
         customXML = CustomXMLParser(customSlide.text)
         verseList = customXML.get_verses()
         raw_slides = [verse[1] for verse in verseList]
-        service_item.title = title
         for slide in raw_slides:
             service_item.add_from_text(slide[:30], slide)
         if QtCore.QSettings().value(self.settingsSection + u'/display footer',
             QtCore.QVariant(True)).toBool() or credit:
-            raw_footer.append(title + u' ' + credit)
+            service_item.raw_footer.append(u' '.join([title, credit]))
         else:
-            raw_footer.append(u'')
-        service_item.raw_footer = raw_footer
+            service_item.raw_footer.append(u'')
         return True
 
     def onSearchTextButtonClicked(self):


Follow ups