diff --git a/openlp/core/ui/amendthemeform.py b/openlp/core/ui/amendthemeform.py index 8327ef793..e5f289d90 100644 --- a/openlp/core/ui/amendthemeform.py +++ b/openlp/core/ui/amendthemeform.py @@ -1,710 +1,666 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 -""" -OpenLP - Open Source Lyrics Projection -Copyright (c) 2008 Raoul Snyman -Portions copyright (c) 2008 Martin Thompson, Tim Bentley, - -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 -import os, os.path - -from PyQt4 import QtCore, QtGui -from openlp.core.lib import ThemeXML, Renderer, file_to_xml, str_to_bool, \ - translate - -from amendthemedialog import Ui_AmendThemeDialog - -log = logging.getLogger(u'AmendThemeForm') - -class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog): - - def __init__(self, thememanager, parent=None): - QtGui.QDialog.__init__(self, parent) - self.thememanager = thememanager - self.path = None - self.theme = ThemeXML() - self.setupUi(self) - #define signals - #Buttons - QtCore.QObject.connect(self.Color1PushButton , - QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked) - QtCore.QObject.connect(self.Color2PushButton , - QtCore.SIGNAL(u'pressed()'), self.onColor2PushButtonClicked) - QtCore.QObject.connect(self.FontMainColorPushButton, - QtCore.SIGNAL(u'pressed()'), self.onFontMainColorPushButtonClicked) - QtCore.QObject.connect(self.FontFooterColorPushButton, - QtCore.SIGNAL(u'pressed()'), - self.onFontFooterColorPushButtonClicked) - QtCore.QObject.connect(self.OutlineColorPushButton, - QtCore.SIGNAL(u'pressed()'), self.onOutlineColorPushButtonClicked) - QtCore.QObject.connect(self.ShadowColorPushButton, - QtCore.SIGNAL(u'pressed()'), self.onShadowColorPushButtonClicked) - QtCore.QObject.connect(self.ImageToolButton, - QtCore.SIGNAL(u'pressed()'), self.onImageToolButtonClicked) - #Combo boxes - QtCore.QObject.connect(self.BackgroundComboBox, - QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected) - QtCore.QObject.connect(self.BackgroundTypeComboBox, - QtCore.SIGNAL(u'activated(int)'), - self.onBackgroundTypeComboBoxSelected) - QtCore.QObject.connect(self.GradientComboBox, - QtCore.SIGNAL(u'activated(int)'), self.onGradientComboBoxSelected) - QtCore.QObject.connect(self.FontMainComboBox, - QtCore.SIGNAL(u'activated(int)'), self.onFontMainComboBoxSelected) - QtCore.QObject.connect(self.FontMainWeightComboBox, - QtCore.SIGNAL(u'activated(int)'), - self.onFontMainWeightComboBoxSelected) - QtCore.QObject.connect(self.FontFooterComboBox, - QtCore.SIGNAL(u'activated(int)'), self.onFontFooterComboBoxSelected) - QtCore.QObject.connect(self.FontFooterWeightComboBox, - QtCore.SIGNAL(u'activated(int)'), - self.onFontFooterWeightComboBoxSelected) - QtCore.QObject.connect(self.HorizontalComboBox, - QtCore.SIGNAL(u'activated(int)'), self.onHorizontalComboBoxSelected) - QtCore.QObject.connect(self.VerticalComboBox, - QtCore.SIGNAL(u'activated(int)'), self.onVerticalComboBoxSelected) - #Spin boxes - QtCore.QObject.connect(self.FontMainSizeSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontMainSizeSpinBoxChanged) - QtCore.QObject.connect(self.FontFooterSizeSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontFooterSizeSpinBoxChanged) - QtCore.QObject.connect(self.FontMainDefaultCheckBox, - QtCore.SIGNAL(u'stateChanged(int)'), - self.onFontMainDefaultCheckBoxChanged) - QtCore.QObject.connect(self.FontMainXSpinBox, - QtCore.SIGNAL(u'editingFinished()'), self.onFontMainXSpinBoxChanged) - QtCore.QObject.connect(self.FontMainYSpinBox, - QtCore.SIGNAL(u'editingFinished()'), self.onFontMainYSpinBoxChanged) - QtCore.QObject.connect(self.FontMainWidthSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontMainWidthSpinBoxChanged) - QtCore.QObject.connect(self.FontMainHeightSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontMainHeightSpinBoxChanged) - QtCore.QObject.connect(self.FontFooterDefaultCheckBox, - QtCore.SIGNAL(u'stateChanged(int)'), - self.onFontFooterDefaultCheckBoxChanged) - QtCore.QObject.connect(self.FontFooterXSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontFooterXSpinBoxChanged) - QtCore.QObject.connect(self.FontFooterYSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontFooterYSpinBoxChanged) - QtCore.QObject.connect(self.FontFooterWidthSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontFooterWidthSpinBoxChanged) - QtCore.QObject.connect(self.FontFooterHeightSpinBox, - QtCore.SIGNAL(u'editingFinished()'), - self.onFontFooterHeightSpinBoxChanged) - QtCore.QObject.connect(self.OutlineCheckBox, - QtCore.SIGNAL(u'stateChanged(int)'), self.onOutlineCheckBoxChanged) - QtCore.QObject.connect(self.ShadowCheckBox, - QtCore.SIGNAL(u'stateChanged(int)'), self.onShadowCheckBoxChanged) - - def accept(self): - new_theme = ThemeXML() - theme_name = unicode(self.ThemeNameEdit.displayText()) - new_theme.new_document(theme_name) - save_from = None - save_to = None - if self.theme.background_mode == u'transparent': - new_theme.add_background_transparent() - else: - if self.theme.background_type == u'solid': - new_theme.add_background_solid( - unicode(self.theme.background_color)) - elif self.theme.background_type == u'gradient': - new_theme.add_background_gradient( - unicode(self.theme.background_startColor), - unicode(self.theme.background_endColor), - self.theme.background_direction) - else: - (path, filename) = \ - os.path.split(unicode(self.theme.background_filename)) - new_theme.add_background_image(filename) - save_to= os.path.join(self.path, theme_name, filename ) - save_from = self.theme.background_filename - - new_theme.add_font(unicode(self.theme.font_main_name), - unicode(self.theme.font_main_color), - unicode(self.theme.font_main_proportion), - unicode(self.theme.font_main_override), u'main', - unicode(self.theme.font_main_weight), - unicode(self.theme.font_main_italics), - unicode(self.theme.font_main_x), - unicode(self.theme.font_main_y), - unicode(self.theme.font_main_width), - unicode(self.theme.font_main_height)) - new_theme.add_font(unicode(self.theme.font_footer_name), - unicode(self.theme.font_footer_color), - unicode(self.theme.font_footer_proportion), - unicode(self.theme.font_footer_override), u'footer', - unicode(self.theme.font_footer_weight), - unicode(self.theme.font_footer_italics), - unicode(self.theme.font_footer_x), - unicode(self.theme.font_footer_y), - unicode(self.theme.font_footer_width), - unicode(self.theme.font_footer_height) ) - new_theme.add_display(unicode(self.theme.display_shadow), - unicode(self.theme.display_shadow_color), - unicode(self.theme.display_outline), - unicode(self.theme.display_outline_color), - unicode(self.theme.display_horizontalAlign), - unicode(self.theme.display_verticalAlign), - unicode(self.theme.display_wrapStyle)) - theme = new_theme.extract_xml() - pretty_theme = new_theme.extract_formatted_xml() - if self.thememanager.saveTheme(theme_name, theme, pretty_theme, - save_from, save_to) is not False: - return QtGui.QDialog.accept(self) - - def loadTheme(self, theme): - log.debug(u'LoadTheme %s', theme) - if theme == None: - self.theme.parse(self.baseTheme()) - else: - xml_file = os.path.join(self.path, theme, theme + u'.xml') - xml = file_to_xml(xml_file) - self.theme.parse(xml) - self.theme.extend_image_filename(self.path) - self.cleanTheme(self.theme) - self.allowPreview = False - self.paintUi(self.theme) - self.allowPreview = True - self.previewTheme(self.theme) - - def cleanTheme(self, theme): - self.theme.background_color = theme.background_color.strip() - self.theme.background_direction = theme.background_direction.strip() - self.theme.background_endColor = theme.background_endColor.strip() - if theme.background_filename: - self.theme.background_filename = theme.background_filename.strip() - #self.theme.background_mode - self.theme.background_startColor = theme.background_startColor.strip() - #self.theme.background_type - self.theme.display_display = theme.display_display.strip() - self.theme.display_horizontalAlign = \ - theme.display_horizontalAlign.strip() - self.theme.display_outline = str_to_bool(theme.display_outline) - #self.theme.display_outline_color - self.theme.display_shadow = str_to_bool(theme.display_shadow) - #self.theme.display_shadow_color - self.theme.display_verticalAlign = \ - theme.display_verticalAlign.strip() - self.theme.display_wrapStyle = theme.display_wrapStyle.strip() - self.theme.font_footer_color = theme.font_footer_color.strip() - self.theme.font_footer_height = theme.font_footer_height.strip() - self.theme.font_footer_italics = str_to_bool(theme.font_footer_italics) - self.theme.font_footer_name = theme.font_footer_name.strip() - #self.theme.font_footer_override - self.theme.font_footer_proportion = \ - theme.font_footer_proportion.strip() - self.theme.font_footer_weight = theme.font_footer_weight.strip() - self.theme.font_footer_width = theme.font_footer_width.strip() - self.theme.font_footer_x = theme.font_footer_x.strip() - self.theme.font_footer_y = theme.font_footer_y.strip() - self.theme.font_main_color = theme.font_main_color.strip() - self.theme.font_main_height = theme.font_main_height.strip() - self.theme.font_main_italics = str_to_bool(theme.font_main_italics) - self.theme.font_main_name = theme.font_main_name.strip() - #self.theme.font_main_override - self.theme.font_main_proportion = theme.font_main_proportion.strip() - self.theme.font_main_weight = theme.font_main_weight.strip() - self.theme.font_main_x = theme.font_main_x.strip() - self.theme.font_main_y = theme.font_main_y.strip() - #self.theme.theme_mode - self.theme.theme_name = theme.theme_name.strip() - #self.theme.theme_version - - def onImageToolButtonClicked(self): - filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file') - if filename != "": - self.ImageLineEdit.setText(filename) - self.theme.background_filename = filename - self.previewTheme(self.theme) - # - #Main Font Tab - # - def onFontMainComboBoxSelected(self): - self.theme.font_main_name = self.FontMainComboBox.currentFont().family() - self.previewTheme(self.theme) - - def onFontMainWeightComboBoxSelected(self, value): - if value == 0: - self.theme.font_main_weight = u'Normal' - self.theme.font_main_italics = False - elif value == 1: - self.theme.font_main_weight = u'Bold' - self.theme.font_main_italics = False - elif value == 2: - self.theme.font_main_weight = u'Normal' - self.theme.font_main_italics = True - else: - self.theme.font_main_weight = u'Bold' - self.theme.font_main_italics = True - self.previewTheme(self.theme) - - def onFontMainColorPushButtonClicked(self): - self.theme.font_main_color = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.font_main_color), self).name() - - self.FontMainColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(self.theme.font_main_color)) - self.previewTheme(self.theme) - - def onFontMainSizeSpinBoxChanged(self): - if self.theme.font_main_proportion != self.FontMainSizeSpinBox.value(): - self.theme.font_main_proportion = self.FontMainSizeSpinBox.value() - self.previewTheme(self.theme) - - def onFontMainDefaultCheckBoxChanged(self, value): - if value == 2: # checked - self.theme.font_main_override = False - else: - self.theme.font_main_override = True - - if int(self.theme.font_main_x) == 0 and \ - int(self.theme.font_main_y) == 0 and \ - int(self.theme.font_main_width) == 0 and \ - int(self.theme.font_main_height) == 0: - self.theme.font_main_x = u'10' - self.theme.font_main_y = u'10' - self.theme.font_main_width = u'1024' - self.theme.font_main_height = u'730' - self.FontMainXSpinBox.setValue(int(self.theme.font_main_x)) - self.FontMainYSpinBox.setValue(int(self.theme.font_main_y)) - self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width)) - self.FontMainHeightSpinBox.setValue(int( - self.theme.font_main_height)) - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onFontMainXSpinBoxChanged(self): - if self.theme.font_main_x != self.FontMainXSpinBox.value(): - self.theme.font_main_x = self.FontMainXSpinBox.value() - self.previewTheme(self.theme) - - def onFontMainYSpinBoxChanged(self): - if self.theme.font_main_y != self.FontMainYSpinBox.value(): - self.theme.font_main_y = self.FontMainYSpinBox.value() - self.previewTheme(self.theme) - - def onFontMainWidthSpinBoxChanged(self): - if self.theme.font_main_width != self.FontMainWidthSpinBox.value(): - self.theme.font_main_width = self.FontMainWidthSpinBox.value() - self.previewTheme(self.theme) - - def onFontMainHeightSpinBoxChanged(self): - if self.theme.font_main_height != self.FontMainHeightSpinBox.value(): - self.theme.font_main_height = self.FontMainHeightSpinBox.value() - self.previewTheme(self.theme) - # - #Footer Font Tab - # - def onFontFooterComboBoxSelected(self): - self.theme.font_footer_name = \ - self.FontFooterComboBox.currentFont().family() - self.previewTheme(self.theme) - - def onFontFooterWeightComboBoxSelected(self, value): - if value == 0: - self.theme.font_footer_weight = u'Normal' - self.theme.font_footer_italics = False - elif value == 1: - self.theme.font_footer_weight = u'Bold' - self.theme.font_footer_italics = False - elif value == 2: - self.theme.font_footer_weight = u'Normal' - self.theme.font_footer_italics = True - else: - self.theme.font_footer_weight = u'Bold' - self.theme.font_footer_italics = True - self.previewTheme(self.theme) - - def onFontFooterColorPushButtonClicked(self): - self.theme.font_footer_color = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.font_footer_color), self).name() - - self.FontFooterColorPushButton.setStyleSheet( - 'background-color: %s' % unicode(self.theme.font_footer_color)) - self.previewTheme(self.theme) - - def onFontFooterSizeSpinBoxChanged(self): - if self.theme.font_footer_proportion != \ - self.FontFooterSizeSpinBox.value(): - self.theme.font_footer_proportion = \ - self.FontFooterSizeSpinBox.value() - self.previewTheme(self.theme) - - def onFontFooterDefaultCheckBoxChanged(self, value): - if value == 2: # checked - self.theme.font_footer_override = False - else: - self.theme.font_footer_override = True - - if int(self.theme.font_footer_x) == 0 and \ - int(self.theme.font_footer_y) == 0 and \ - int(self.theme.font_footer_width) == 0 and \ - int(self.theme.font_footer_height) == 0: - self.theme.font_footer_x = u'10' - self.theme.font_footer_y = u'730' - self.theme.font_footer_width = u'1024' - self.theme.font_footer_height = u'38' - - self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x)) - self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y)) - self.FontFooterWidthSpinBox.setValue(int( - self.theme.font_footer_width)) - self.FontFooterHeightSpinBox.setValue(int( - self.theme.font_footer_height)) - - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onFontFooterXSpinBoxChanged(self): - if self.theme.font_footer_x != self.FontFooterXSpinBox.value(): - self.theme.font_footer_x = self.FontFooterXSpinBox.value() - self.previewTheme(self.theme) - - def onFontFooterYSpinBoxChanged(self): - if self.theme.font_footer_y != self.FontFooterYSpinBox.value(): - self.theme.font_footer_y = self.FontFooterYSpinBox.value() - self.previewTheme(self.theme) - - def onFontFooterWidthSpinBoxChanged(self): - if self.theme.font_footer_width != self.FontFooterWidthSpinBox.value(): - self.theme.font_footer_width = self.FontFooterWidthSpinBox.value() - self.previewTheme(self.theme) - - def onFontFooterHeightSpinBoxChanged(self): - if self.theme.font_footer_height != \ - self.FontFooterHeightSpinBox.value(): - self.theme.font_footer_height = self.FontFooterHeightSpinBox.value() - self.previewTheme(self.theme) - # - #Background Tab - # - def onGradientComboBoxSelected(self, currentIndex): - self.setBackground(self.BackgroundTypeComboBox.currentIndex(), - currentIndex) - - def onBackgroundComboBoxSelected(self, currentIndex): - if currentIndex == 0: # Opaque - self.theme.background_mode = u'opaque' - else: - self.theme.background_mode = u'transparent' - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onBackgroundTypeComboBoxSelected(self, currentIndex): - self.setBackground(currentIndex, self.GradientComboBox.currentIndex()) - - def setBackground(self, background, gradient): - if background == 0: # Solid - self.theme.background_type = u'solid' - if self.theme.background_color is None : - self.theme.background_color = u'#000000' - elif background == 1: # Gradient - self.theme.background_type = u'gradient' - if gradient == 0: # Horizontal - self.theme.background_direction = u'horizontal' - elif gradient == 1: # vertical - self.theme.background_direction = u'vertical' - else: - self.theme.background_direction = u'circular' - if self.theme.background_startColor is None : - self.theme.background_startColor = u'#000000' - if self.theme.background_endColor is None : - self.theme.background_endColor = u'#ff0000' - else: - self.theme.background_type = u'image' - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onColor1PushButtonClicked(self): - if self.theme.background_type == u'solid': - self.theme.background_color = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.background_color), self).name() - self.Color1PushButton.setStyleSheet( - u'background-color: %s' % unicode(self.theme.background_color)) - else: - self.theme.background_startColor = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.background_startColor), self).name() - self.Color1PushButton.setStyleSheet( - u'background-color: %s' % \ - unicode(self.theme.background_startColor)) - - self.previewTheme(self.theme) - - def onColor2PushButtonClicked(self): - self.theme.background_endColor = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.background_endColor), self).name() - self.Color2PushButton.setStyleSheet( - u'background-color: %s' % unicode(self.theme.background_endColor)) - - self.previewTheme(self.theme) - # - #Other Tab - # - def onOutlineCheckBoxChanged(self, value): - if value == 2: # checked - self.theme.display_outline = True - else: - self.theme.display_outline = False - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onOutlineColorPushButtonClicked(self): - self.theme.display_outline_color = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.display_outline_color), self).name() - self.OutlineColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(self.theme.display_outline_color)) - self.previewTheme(self.theme) - - def onShadowCheckBoxChanged(self, value): - if value == 2: # checked - self.theme.display_shadow = True - else: - self.theme.display_shadow = False - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onShadowColorPushButtonClicked(self): - self.theme.display_shadow_color = QtGui.QColorDialog.getColor( - QtGui.QColor(self.theme.display_shadow_color), self).name() - self.ShadowColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(self.theme.display_shadow_color)) - self.previewTheme(self.theme) - - def onHorizontalComboBoxSelected(self, currentIndex): - self.theme.display_horizontalAlign = currentIndex - self.stateChanging(self.theme) - self.previewTheme(self.theme) - - def onVerticalComboBoxSelected(self, currentIndex): - self.theme.display_verticalAlign = currentIndex - self.stateChanging(self.theme) - self.previewTheme(self.theme) - # - #Local Methods - # - def baseTheme(self): - log.debug(u'base theme created') - newtheme = ThemeXML() - newtheme.new_document(u'New Theme') - newtheme.add_background_solid(unicode(u'#000000')) - newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'), - unicode(30), u'False') - newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'), - unicode(12), u'False', u'footer') - newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False', - unicode(u'#FFFFFF'), - unicode(0), unicode(0), unicode(0)) - - return newtheme.extract_xml() - - def paintUi(self, theme): - self.stateChanging(theme) - self.ThemeNameEdit.setText(self.theme.theme_name) - if self.theme.background_mode == u'opaque': - self.BackgroundComboBox.setCurrentIndex(0) - else: - self.BackgroundComboBox.setCurrentIndex(1) - - if theme.background_type == u'solid': - self.BackgroundTypeComboBox.setCurrentIndex(0) - elif theme.background_type == u'gradient': - self.BackgroundTypeComboBox.setCurrentIndex(1) - else: - self.BackgroundTypeComboBox.setCurrentIndex(2) - - if self.theme.background_direction == u'horizontal': - self.GradientComboBox.setCurrentIndex(0) - elif self.theme.background_direction == u'vertical': - self.GradientComboBox.setCurrentIndex(1) - else: - self.GradientComboBox.setCurrentIndex(2) - - self.FontMainSizeSpinBox.setValue(int(self.theme.font_main_proportion)) - if not self.theme.font_main_italics and \ - self.theme.font_main_weight == u'Normal': - self.FontMainWeightComboBox.setCurrentIndex(0) - elif not self.theme.font_main_italics and \ - self.theme.font_main_weight == u'Bold': - self.FontMainWeightComboBox.setCurrentIndex(1) - elif self.theme.font_main_italics and \ - self.theme.font_main_weight == u'Normal': - self.FontMainWeightComboBox.setCurrentIndex(2) - else: - self.FontMainWeightComboBox.setCurrentIndex(3) - - self.FontMainXSpinBox.setValue(int(self.theme.font_main_x)) - self.FontMainYSpinBox.setValue(int(self.theme.font_main_y)) - self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width)) - self.FontMainHeightSpinBox.setValue(int(self.theme.font_main_height)) - self.FontFooterSizeSpinBox.setValue(int( - self.theme.font_footer_proportion)) - if not self.theme.font_footer_italics and \ - self.theme.font_footer_weight == u'Normal': - self.FontFooterWeightComboBox.setCurrentIndex(0) - elif not self.theme.font_footer_italics and \ - self.theme.font_footer_weight == u'Bold': - self.FontFooterWeightComboBox.setCurrentIndex(1) - elif self.theme.font_footer_italics and \ - self.theme.font_footer_weight == u'Normal': - self.FontFooterWeightComboBox.setCurrentIndex(2) - else: - self.FontFooterWeightComboBox.setCurrentIndex(3) - self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x)) - self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y)) - self.FontFooterWidthSpinBox.setValue(int(self.theme.font_footer_width)) - self.FontFooterHeightSpinBox.setValue(int( - self.theme.font_footer_height)) - self.FontMainColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(theme.font_main_color)) - self.FontFooterColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(theme.font_footer_color)) - - if self.theme.font_main_override == False: - self.FontMainDefaultCheckBox.setChecked(True) - else: - self.FontMainDefaultCheckBox.setChecked(False) - - if self.theme.font_footer_override == False: - self.FontFooterDefaultCheckBox.setChecked(True) - else: - self.FontFooterDefaultCheckBox.setChecked(False) - - self.OutlineColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(theme.display_outline_color)) - self.ShadowColorPushButton.setStyleSheet( - u'background-color: %s' % unicode(theme.display_shadow_color)) - - if self.theme.display_outline: - self.OutlineCheckBox.setChecked(True) - self.OutlineColorPushButton.setEnabled(True) - else: - self.OutlineCheckBox.setChecked(False) - self.OutlineColorPushButton.setEnabled(False) - - if self.theme.display_shadow: - self.ShadowCheckBox.setChecked(True) - self.ShadowColorPushButton.setEnabled(True) - else: - self.ShadowCheckBox.setChecked(False) - self.ShadowColorPushButton.setEnabled(False) - - self.HorizontalComboBox.setCurrentIndex(int( - self.theme.display_horizontalAlign)) - self.VerticalComboBox.setCurrentIndex(int( - self.theme.display_verticalAlign)) - - def stateChanging(self, theme): - if theme.background_mode == u'transparent': - self.Color1Label.setVisible(False) - self.Color1PushButton.setVisible(False) - self.Color2Label.setVisible(False) - self.Color2PushButton.setVisible(False) - self.ImageLabel.setVisible(False) - self.ImageLineEdit.setVisible(False) - self.ImageFilenameWidget.setVisible(False) - self.GradientLabel.setVisible(False) - self.GradientComboBox.setVisible(False) - self.BackgroundTypeComboBox.setVisible(False) - self.BackgroundTypeLabel.setVisible(False) - else: - self.BackgroundTypeComboBox.setVisible(True) - self.BackgroundTypeLabel.setVisible(True) - if theme.background_type == u'solid': - self.Color1PushButton.setStyleSheet( - u'background-color: %s' % unicode(theme.background_color)) - self.Color1Label.setText(translate(u'ThemeManager', - u'Background Color:')) - self.Color1Label.setVisible(True) - self.Color1PushButton.setVisible(True) - self.Color2Label.setVisible(False) - self.Color2PushButton.setVisible(False) - self.ImageLabel.setVisible(False) - self.ImageLineEdit.setVisible(False) - self.ImageFilenameWidget.setVisible(False) - self.GradientLabel.setVisible(False) - self.GradientComboBox.setVisible(False) - elif theme.background_type == u'gradient': - self.Color1PushButton.setStyleSheet(u'background-color: %s' \ - % unicode(theme.background_startColor)) - self.Color2PushButton.setStyleSheet(u'background-color: %s' \ - % unicode(theme.background_endColor)) - self.Color1Label.setText(translate(u'ThemeManager', - u'First Color:')) - self.Color2Label.setText(translate(u'ThemeManager', - u'Second Color:')) - self.Color1Label.setVisible(True) - self.Color1PushButton.setVisible(True) - self.Color2Label.setVisible(True) - self.Color2PushButton.setVisible(True) - self.ImageLabel.setVisible(False) - self.ImageLineEdit.setVisible(False) - self.ImageFilenameWidget.setVisible(False) - self.GradientLabel.setVisible(True) - self.GradientComboBox.setVisible(True) - else: # must be image - self.Color1Label.setVisible(False) - self.Color1PushButton.setVisible(False) - self.Color2Label.setVisible(False) - self.Color2PushButton.setVisible(False) - self.ImageLabel.setVisible(True) - self.ImageLineEdit.setVisible(True) - self.ImageFilenameWidget.setVisible(True) - self.GradientLabel.setVisible(False) - self.GradientComboBox.setVisible(False) - - if theme.font_main_override == False: - self.FontMainXSpinBox.setEnabled(False) - self.FontMainYSpinBox.setEnabled(False) - self.FontMainWidthSpinBox.setEnabled(False) - self.FontMainHeightSpinBox.setEnabled(False) - else: - self.FontMainXSpinBox.setEnabled(True) - self.FontMainYSpinBox.setEnabled(True) - self.FontMainWidthSpinBox.setEnabled(True) - self.FontMainHeightSpinBox.setEnabled(True) - - if theme.font_footer_override == False: - self.FontFooterXSpinBox.setEnabled(False) - self.FontFooterYSpinBox.setEnabled(False) - self.FontFooterWidthSpinBox.setEnabled(False) - self.FontFooterHeightSpinBox.setEnabled(False) - else: - self.FontFooterXSpinBox.setEnabled(True) - self.FontFooterYSpinBox.setEnabled(True) - self.FontFooterWidthSpinBox.setEnabled(True) - self.FontFooterHeightSpinBox.setEnabled(True) - - if self.theme.display_outline: - self.OutlineColorPushButton.setEnabled(True) - else: - self.OutlineColorPushButton.setEnabled(False) - - if self.theme.display_shadow: - self.ShadowColorPushButton.setEnabled(True) - else: - self.ShadowColorPushButton.setEnabled(False) - - def previewTheme(self, theme): - if self.allowPreview: - frame = self.thememanager.generateImage(theme) - self.ThemePreview.setPixmap(QtGui.QPixmap.fromImage(frame)) +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 +""" +OpenLP - Open Source Lyrics Projection +Copyright (c) 2008 Raoul Snyman +Portions copyright (c) 2008 Martin Thompson, Tim Bentley, + +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 +import os, os.path + +from PyQt4 import QtCore, QtGui +from openlp.core.lib import ThemeXML, Renderer, file_to_xml, translate + +from amendthemedialog import Ui_AmendThemeDialog + +log = logging.getLogger(u'AmendThemeForm') + +class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog): + + def __init__(self, thememanager, parent=None): + QtGui.QDialog.__init__(self, parent) + self.thememanager = thememanager + self.path = None + self.theme = ThemeXML() + self.setupUi(self) + #define signals + #Buttons + QtCore.QObject.connect(self.Color1PushButton , + QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked) + QtCore.QObject.connect(self.Color2PushButton , + QtCore.SIGNAL(u'pressed()'), self.onColor2PushButtonClicked) + QtCore.QObject.connect(self.FontMainColorPushButton, + QtCore.SIGNAL(u'pressed()'), self.onFontMainColorPushButtonClicked) + QtCore.QObject.connect(self.FontFooterColorPushButton, + QtCore.SIGNAL(u'pressed()'), + self.onFontFooterColorPushButtonClicked) + QtCore.QObject.connect(self.OutlineColorPushButton, + QtCore.SIGNAL(u'pressed()'), self.onOutlineColorPushButtonClicked) + QtCore.QObject.connect(self.ShadowColorPushButton, + QtCore.SIGNAL(u'pressed()'), self.onShadowColorPushButtonClicked) + QtCore.QObject.connect(self.ImageToolButton, + QtCore.SIGNAL(u'pressed()'), self.onImageToolButtonClicked) + #Combo boxes + QtCore.QObject.connect(self.BackgroundComboBox, + QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected) + QtCore.QObject.connect(self.BackgroundTypeComboBox, + QtCore.SIGNAL(u'activated(int)'), + self.onBackgroundTypeComboBoxSelected) + QtCore.QObject.connect(self.GradientComboBox, + QtCore.SIGNAL(u'activated(int)'), self.onGradientComboBoxSelected) + QtCore.QObject.connect(self.FontMainComboBox, + QtCore.SIGNAL(u'activated(int)'), self.onFontMainComboBoxSelected) + QtCore.QObject.connect(self.FontMainWeightComboBox, + QtCore.SIGNAL(u'activated(int)'), + self.onFontMainWeightComboBoxSelected) + QtCore.QObject.connect(self.FontFooterComboBox, + QtCore.SIGNAL(u'activated(int)'), self.onFontFooterComboBoxSelected) + QtCore.QObject.connect(self.FontFooterWeightComboBox, + QtCore.SIGNAL(u'activated(int)'), + self.onFontFooterWeightComboBoxSelected) + QtCore.QObject.connect(self.HorizontalComboBox, + QtCore.SIGNAL(u'activated(int)'), self.onHorizontalComboBoxSelected) + QtCore.QObject.connect(self.VerticalComboBox, + QtCore.SIGNAL(u'activated(int)'), self.onVerticalComboBoxSelected) + #Spin boxes + QtCore.QObject.connect(self.FontMainSizeSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontMainSizeSpinBoxChanged) + QtCore.QObject.connect(self.FontFooterSizeSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontFooterSizeSpinBoxChanged) + QtCore.QObject.connect(self.FontMainDefaultCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onFontMainDefaultCheckBoxChanged) + QtCore.QObject.connect(self.FontMainXSpinBox, + QtCore.SIGNAL(u'editingFinished()'), self.onFontMainXSpinBoxChanged) + QtCore.QObject.connect(self.FontMainYSpinBox, + QtCore.SIGNAL(u'editingFinished()'), self.onFontMainYSpinBoxChanged) + QtCore.QObject.connect(self.FontMainWidthSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontMainWidthSpinBoxChanged) + QtCore.QObject.connect(self.FontMainHeightSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontMainHeightSpinBoxChanged) + QtCore.QObject.connect(self.FontFooterDefaultCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onFontFooterDefaultCheckBoxChanged) + QtCore.QObject.connect(self.FontFooterXSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontFooterXSpinBoxChanged) + QtCore.QObject.connect(self.FontFooterYSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontFooterYSpinBoxChanged) + QtCore.QObject.connect(self.FontFooterWidthSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontFooterWidthSpinBoxChanged) + QtCore.QObject.connect(self.FontFooterHeightSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.onFontFooterHeightSpinBoxChanged) + QtCore.QObject.connect(self.OutlineCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), self.onOutlineCheckBoxChanged) + QtCore.QObject.connect(self.ShadowCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), self.onShadowCheckBoxChanged) + + def accept(self): + new_theme = ThemeXML() + theme_name = unicode(self.ThemeNameEdit.displayText()) + new_theme.new_document(theme_name) + save_from = None + save_to = None + if self.theme.background_mode == u'transparent': + new_theme.add_background_transparent() + else: + if self.theme.background_type == u'solid': + new_theme.add_background_solid( + unicode(self.theme.background_color)) + elif self.theme.background_type == u'gradient': + new_theme.add_background_gradient( + unicode(self.theme.background_startColor), + unicode(self.theme.background_endColor), + self.theme.background_direction) + else: + (path, filename) = \ + os.path.split(unicode(self.theme.background_filename)) + new_theme.add_background_image(filename) + save_to= os.path.join(self.path, theme_name, filename ) + save_from = self.theme.background_filename + + new_theme.add_font(unicode(self.theme.font_main_name), + unicode(self.theme.font_main_color), + unicode(self.theme.font_main_proportion), + unicode(self.theme.font_main_override), u'main', + unicode(self.theme.font_main_weight), + unicode(self.theme.font_main_italics), + unicode(self.theme.font_main_x), + unicode(self.theme.font_main_y), + unicode(self.theme.font_main_width), + unicode(self.theme.font_main_height)) + new_theme.add_font(unicode(self.theme.font_footer_name), + unicode(self.theme.font_footer_color), + unicode(self.theme.font_footer_proportion), + unicode(self.theme.font_footer_override), u'footer', + unicode(self.theme.font_footer_weight), + unicode(self.theme.font_footer_italics), + unicode(self.theme.font_footer_x), + unicode(self.theme.font_footer_y), + unicode(self.theme.font_footer_width), + unicode(self.theme.font_footer_height) ) + new_theme.add_display(unicode(self.theme.display_shadow), + unicode(self.theme.display_shadow_color), + unicode(self.theme.display_outline), + unicode(self.theme.display_outline_color), + unicode(self.theme.display_horizontalAlign), + unicode(self.theme.display_verticalAlign), + unicode(self.theme.display_wrapStyle)) + theme = new_theme.extract_xml() + pretty_theme = new_theme.extract_formatted_xml() + if self.thememanager.saveTheme(theme_name, theme, pretty_theme, + save_from, save_to) is not False: + return QtGui.QDialog.accept(self) + + def loadTheme(self, theme): + log.debug(u'LoadTheme %s', theme) + if theme == None: + self.theme.parse(self.baseTheme()) + else: + xml_file = os.path.join(self.path, theme, theme + u'.xml') + xml = file_to_xml(xml_file) + self.theme.parse(xml) + self.theme.extend_image_filename(self.path) + self.thememanager.cleanTheme(self.theme) + self.allowPreview = False + self.paintUi(self.theme) + self.allowPreview = True + self.previewTheme(self.theme) + + def onImageToolButtonClicked(self): + filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file') + if filename != "": + self.ImageLineEdit.setText(filename) + self.theme.background_filename = filename + self.previewTheme(self.theme) + # + #Main Font Tab + # + def onFontMainComboBoxSelected(self): + self.theme.font_main_name = self.FontMainComboBox.currentFont().family() + self.previewTheme(self.theme) + + def onFontMainWeightComboBoxSelected(self, value): + if value == 0: + self.theme.font_main_weight = u'Normal' + self.theme.font_main_italics = False + elif value == 1: + self.theme.font_main_weight = u'Bold' + self.theme.font_main_italics = False + elif value == 2: + self.theme.font_main_weight = u'Normal' + self.theme.font_main_italics = True + else: + self.theme.font_main_weight = u'Bold' + self.theme.font_main_italics = True + self.previewTheme(self.theme) + + def onFontMainColorPushButtonClicked(self): + self.theme.font_main_color = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.font_main_color), self).name() + + self.FontMainColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(self.theme.font_main_color)) + self.previewTheme(self.theme) + + def onFontMainSizeSpinBoxChanged(self): + if self.theme.font_main_proportion != self.FontMainSizeSpinBox.value(): + self.theme.font_main_proportion = self.FontMainSizeSpinBox.value() + self.previewTheme(self.theme) + + def onFontMainDefaultCheckBoxChanged(self, value): + if value == 2: # checked + self.theme.font_main_override = False + else: + self.theme.font_main_override = True + + if int(self.theme.font_main_x) == 0 and \ + int(self.theme.font_main_y) == 0 and \ + int(self.theme.font_main_width) == 0 and \ + int(self.theme.font_main_height) == 0: + self.theme.font_main_x = u'10' + self.theme.font_main_y = u'10' + self.theme.font_main_width = u'1024' + self.theme.font_main_height = u'730' + self.FontMainXSpinBox.setValue(int(self.theme.font_main_x)) + self.FontMainYSpinBox.setValue(int(self.theme.font_main_y)) + self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width)) + self.FontMainHeightSpinBox.setValue(int( + self.theme.font_main_height)) + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onFontMainXSpinBoxChanged(self): + if self.theme.font_main_x != self.FontMainXSpinBox.value(): + self.theme.font_main_x = self.FontMainXSpinBox.value() + self.previewTheme(self.theme) + + def onFontMainYSpinBoxChanged(self): + if self.theme.font_main_y != self.FontMainYSpinBox.value(): + self.theme.font_main_y = self.FontMainYSpinBox.value() + self.previewTheme(self.theme) + + def onFontMainWidthSpinBoxChanged(self): + if self.theme.font_main_width != self.FontMainWidthSpinBox.value(): + self.theme.font_main_width = self.FontMainWidthSpinBox.value() + self.previewTheme(self.theme) + + def onFontMainHeightSpinBoxChanged(self): + if self.theme.font_main_height != self.FontMainHeightSpinBox.value(): + self.theme.font_main_height = self.FontMainHeightSpinBox.value() + self.previewTheme(self.theme) + # + #Footer Font Tab + # + def onFontFooterComboBoxSelected(self): + self.theme.font_footer_name = \ + self.FontFooterComboBox.currentFont().family() + self.previewTheme(self.theme) + + def onFontFooterWeightComboBoxSelected(self, value): + if value == 0: + self.theme.font_footer_weight = u'Normal' + self.theme.font_footer_italics = False + elif value == 1: + self.theme.font_footer_weight = u'Bold' + self.theme.font_footer_italics = False + elif value == 2: + self.theme.font_footer_weight = u'Normal' + self.theme.font_footer_italics = True + else: + self.theme.font_footer_weight = u'Bold' + self.theme.font_footer_italics = True + self.previewTheme(self.theme) + + def onFontFooterColorPushButtonClicked(self): + self.theme.font_footer_color = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.font_footer_color), self).name() + + self.FontFooterColorPushButton.setStyleSheet( + 'background-color: %s' % unicode(self.theme.font_footer_color)) + self.previewTheme(self.theme) + + def onFontFooterSizeSpinBoxChanged(self): + if self.theme.font_footer_proportion != \ + self.FontFooterSizeSpinBox.value(): + self.theme.font_footer_proportion = \ + self.FontFooterSizeSpinBox.value() + self.previewTheme(self.theme) + + def onFontFooterDefaultCheckBoxChanged(self, value): + if value == 2: # checked + self.theme.font_footer_override = False + else: + self.theme.font_footer_override = True + + if int(self.theme.font_footer_x) == 0 and \ + int(self.theme.font_footer_y) == 0 and \ + int(self.theme.font_footer_width) == 0 and \ + int(self.theme.font_footer_height) == 0: + self.theme.font_footer_x = u'10' + self.theme.font_footer_y = u'730' + self.theme.font_footer_width = u'1024' + self.theme.font_footer_height = u'38' + + self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x)) + self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y)) + self.FontFooterWidthSpinBox.setValue(int( + self.theme.font_footer_width)) + self.FontFooterHeightSpinBox.setValue(int( + self.theme.font_footer_height)) + + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onFontFooterXSpinBoxChanged(self): + if self.theme.font_footer_x != self.FontFooterXSpinBox.value(): + self.theme.font_footer_x = self.FontFooterXSpinBox.value() + self.previewTheme(self.theme) + + def onFontFooterYSpinBoxChanged(self): + if self.theme.font_footer_y != self.FontFooterYSpinBox.value(): + self.theme.font_footer_y = self.FontFooterYSpinBox.value() + self.previewTheme(self.theme) + + def onFontFooterWidthSpinBoxChanged(self): + if self.theme.font_footer_width != self.FontFooterWidthSpinBox.value(): + self.theme.font_footer_width = self.FontFooterWidthSpinBox.value() + self.previewTheme(self.theme) + + def onFontFooterHeightSpinBoxChanged(self): + if self.theme.font_footer_height != \ + self.FontFooterHeightSpinBox.value(): + self.theme.font_footer_height = self.FontFooterHeightSpinBox.value() + self.previewTheme(self.theme) + # + #Background Tab + # + def onGradientComboBoxSelected(self, currentIndex): + self.setBackground(self.BackgroundTypeComboBox.currentIndex(), + currentIndex) + + def onBackgroundComboBoxSelected(self, currentIndex): + if currentIndex == 0: # Opaque + self.theme.background_mode = u'opaque' + else: + self.theme.background_mode = u'transparent' + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onBackgroundTypeComboBoxSelected(self, currentIndex): + self.setBackground(currentIndex, self.GradientComboBox.currentIndex()) + + def setBackground(self, background, gradient): + if background == 0: # Solid + self.theme.background_type = u'solid' + if self.theme.background_color is None : + self.theme.background_color = u'#000000' + elif background == 1: # Gradient + self.theme.background_type = u'gradient' + if gradient == 0: # Horizontal + self.theme.background_direction = u'horizontal' + elif gradient == 1: # vertical + self.theme.background_direction = u'vertical' + else: + self.theme.background_direction = u'circular' + if self.theme.background_startColor is None : + self.theme.background_startColor = u'#000000' + if self.theme.background_endColor is None : + self.theme.background_endColor = u'#ff0000' + else: + self.theme.background_type = u'image' + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onColor1PushButtonClicked(self): + if self.theme.background_type == u'solid': + self.theme.background_color = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.background_color), self).name() + self.Color1PushButton.setStyleSheet( + u'background-color: %s' % unicode(self.theme.background_color)) + else: + self.theme.background_startColor = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.background_startColor), self).name() + self.Color1PushButton.setStyleSheet( + u'background-color: %s' % \ + unicode(self.theme.background_startColor)) + + self.previewTheme(self.theme) + + def onColor2PushButtonClicked(self): + self.theme.background_endColor = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.background_endColor), self).name() + self.Color2PushButton.setStyleSheet( + u'background-color: %s' % unicode(self.theme.background_endColor)) + + self.previewTheme(self.theme) + # + #Other Tab + # + def onOutlineCheckBoxChanged(self, value): + if value == 2: # checked + self.theme.display_outline = True + else: + self.theme.display_outline = False + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onOutlineColorPushButtonClicked(self): + self.theme.display_outline_color = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.display_outline_color), self).name() + self.OutlineColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(self.theme.display_outline_color)) + self.previewTheme(self.theme) + + def onShadowCheckBoxChanged(self, value): + if value == 2: # checked + self.theme.display_shadow = True + else: + self.theme.display_shadow = False + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onShadowColorPushButtonClicked(self): + self.theme.display_shadow_color = QtGui.QColorDialog.getColor( + QtGui.QColor(self.theme.display_shadow_color), self).name() + self.ShadowColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(self.theme.display_shadow_color)) + self.previewTheme(self.theme) + + def onHorizontalComboBoxSelected(self, currentIndex): + self.theme.display_horizontalAlign = currentIndex + self.stateChanging(self.theme) + self.previewTheme(self.theme) + + def onVerticalComboBoxSelected(self, currentIndex): + self.theme.display_verticalAlign = currentIndex + self.stateChanging(self.theme) + self.previewTheme(self.theme) + # + #Local Methods + # + def baseTheme(self): + log.debug(u'base theme created') + newtheme = ThemeXML() + newtheme.new_document(u'New Theme') + newtheme.add_background_solid(unicode(u'#000000')) + newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'), + unicode(30), u'False') + newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'), + unicode(12), u'False', u'footer') + newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False', + unicode(u'#FFFFFF'), + unicode(0), unicode(0), unicode(0)) + + return newtheme.extract_xml() + + def paintUi(self, theme): + self.stateChanging(theme) + self.ThemeNameEdit.setText(self.theme.theme_name) + if self.theme.background_mode == u'opaque': + self.BackgroundComboBox.setCurrentIndex(0) + else: + self.BackgroundComboBox.setCurrentIndex(1) + + if theme.background_type == u'solid': + self.BackgroundTypeComboBox.setCurrentIndex(0) + elif theme.background_type == u'gradient': + self.BackgroundTypeComboBox.setCurrentIndex(1) + else: + self.BackgroundTypeComboBox.setCurrentIndex(2) + + if self.theme.background_direction == u'horizontal': + self.GradientComboBox.setCurrentIndex(0) + elif self.theme.background_direction == u'vertical': + self.GradientComboBox.setCurrentIndex(1) + else: + self.GradientComboBox.setCurrentIndex(2) + + self.FontMainSizeSpinBox.setValue(int(self.theme.font_main_proportion)) + if not self.theme.font_main_italics and \ + self.theme.font_main_weight == u'Normal': + self.FontMainWeightComboBox.setCurrentIndex(0) + elif not self.theme.font_main_italics and \ + self.theme.font_main_weight == u'Bold': + self.FontMainWeightComboBox.setCurrentIndex(1) + elif self.theme.font_main_italics and \ + self.theme.font_main_weight == u'Normal': + self.FontMainWeightComboBox.setCurrentIndex(2) + else: + self.FontMainWeightComboBox.setCurrentIndex(3) + + self.FontMainXSpinBox.setValue(int(self.theme.font_main_x)) + self.FontMainYSpinBox.setValue(int(self.theme.font_main_y)) + self.FontMainWidthSpinBox.setValue(int(self.theme.font_main_width)) + self.FontMainHeightSpinBox.setValue(int(self.theme.font_main_height)) + self.FontFooterSizeSpinBox.setValue(int( + self.theme.font_footer_proportion)) + if not self.theme.font_footer_italics and \ + self.theme.font_footer_weight == u'Normal': + self.FontFooterWeightComboBox.setCurrentIndex(0) + elif not self.theme.font_footer_italics and \ + self.theme.font_footer_weight == u'Bold': + self.FontFooterWeightComboBox.setCurrentIndex(1) + elif self.theme.font_footer_italics and \ + self.theme.font_footer_weight == u'Normal': + self.FontFooterWeightComboBox.setCurrentIndex(2) + else: + self.FontFooterWeightComboBox.setCurrentIndex(3) + self.FontFooterXSpinBox.setValue(int(self.theme.font_footer_x)) + self.FontFooterYSpinBox.setValue(int(self.theme.font_footer_y)) + self.FontFooterWidthSpinBox.setValue(int(self.theme.font_footer_width)) + self.FontFooterHeightSpinBox.setValue(int( + self.theme.font_footer_height)) + self.FontMainColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(theme.font_main_color)) + self.FontFooterColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(theme.font_footer_color)) + + if self.theme.font_main_override == False: + self.FontMainDefaultCheckBox.setChecked(True) + else: + self.FontMainDefaultCheckBox.setChecked(False) + + if self.theme.font_footer_override == False: + self.FontFooterDefaultCheckBox.setChecked(True) + else: + self.FontFooterDefaultCheckBox.setChecked(False) + + self.OutlineColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(theme.display_outline_color)) + self.ShadowColorPushButton.setStyleSheet( + u'background-color: %s' % unicode(theme.display_shadow_color)) + + if self.theme.display_outline: + self.OutlineCheckBox.setChecked(True) + self.OutlineColorPushButton.setEnabled(True) + else: + self.OutlineCheckBox.setChecked(False) + self.OutlineColorPushButton.setEnabled(False) + + if self.theme.display_shadow: + self.ShadowCheckBox.setChecked(True) + self.ShadowColorPushButton.setEnabled(True) + else: + self.ShadowCheckBox.setChecked(False) + self.ShadowColorPushButton.setEnabled(False) + + self.HorizontalComboBox.setCurrentIndex(int( + self.theme.display_horizontalAlign)) + self.VerticalComboBox.setCurrentIndex(int( + self.theme.display_verticalAlign)) + + def stateChanging(self, theme): + if theme.background_mode == u'transparent': + self.Color1Label.setVisible(False) + self.Color1PushButton.setVisible(False) + self.Color2Label.setVisible(False) + self.Color2PushButton.setVisible(False) + self.ImageLabel.setVisible(False) + self.ImageLineEdit.setVisible(False) + self.ImageFilenameWidget.setVisible(False) + self.GradientLabel.setVisible(False) + self.GradientComboBox.setVisible(False) + self.BackgroundTypeComboBox.setVisible(False) + self.BackgroundTypeLabel.setVisible(False) + else: + self.BackgroundTypeComboBox.setVisible(True) + self.BackgroundTypeLabel.setVisible(True) + if theme.background_type == u'solid': + self.Color1PushButton.setStyleSheet( + u'background-color: %s' % unicode(theme.background_color)) + self.Color1Label.setText(translate(u'ThemeManager', + u'Background Color:')) + self.Color1Label.setVisible(True) + self.Color1PushButton.setVisible(True) + self.Color2Label.setVisible(False) + self.Color2PushButton.setVisible(False) + self.ImageLabel.setVisible(False) + self.ImageLineEdit.setVisible(False) + self.ImageFilenameWidget.setVisible(False) + self.GradientLabel.setVisible(False) + self.GradientComboBox.setVisible(False) + elif theme.background_type == u'gradient': + self.Color1PushButton.setStyleSheet(u'background-color: %s' \ + % unicode(theme.background_startColor)) + self.Color2PushButton.setStyleSheet(u'background-color: %s' \ + % unicode(theme.background_endColor)) + self.Color1Label.setText(translate(u'ThemeManager', + u'First Color:')) + self.Color2Label.setText(translate(u'ThemeManager', + u'Second Color:')) + self.Color1Label.setVisible(True) + self.Color1PushButton.setVisible(True) + self.Color2Label.setVisible(True) + self.Color2PushButton.setVisible(True) + self.ImageLabel.setVisible(False) + self.ImageLineEdit.setVisible(False) + self.ImageFilenameWidget.setVisible(False) + self.GradientLabel.setVisible(True) + self.GradientComboBox.setVisible(True) + else: # must be image + self.Color1Label.setVisible(False) + self.Color1PushButton.setVisible(False) + self.Color2Label.setVisible(False) + self.Color2PushButton.setVisible(False) + self.ImageLabel.setVisible(True) + self.ImageLineEdit.setVisible(True) + self.ImageFilenameWidget.setVisible(True) + self.GradientLabel.setVisible(False) + self.GradientComboBox.setVisible(False) + + if theme.font_main_override == False: + self.FontMainXSpinBox.setEnabled(False) + self.FontMainYSpinBox.setEnabled(False) + self.FontMainWidthSpinBox.setEnabled(False) + self.FontMainHeightSpinBox.setEnabled(False) + else: + self.FontMainXSpinBox.setEnabled(True) + self.FontMainYSpinBox.setEnabled(True) + self.FontMainWidthSpinBox.setEnabled(True) + self.FontMainHeightSpinBox.setEnabled(True) + + if theme.font_footer_override == False: + self.FontFooterXSpinBox.setEnabled(False) + self.FontFooterYSpinBox.setEnabled(False) + self.FontFooterWidthSpinBox.setEnabled(False) + self.FontFooterHeightSpinBox.setEnabled(False) + else: + self.FontFooterXSpinBox.setEnabled(True) + self.FontFooterYSpinBox.setEnabled(True) + self.FontFooterWidthSpinBox.setEnabled(True) + self.FontFooterHeightSpinBox.setEnabled(True) + + if self.theme.display_outline: + self.OutlineColorPushButton.setEnabled(True) + else: + self.OutlineColorPushButton.setEnabled(False) + + if self.theme.display_shadow: + self.ShadowColorPushButton.setEnabled(True) + else: + self.ShadowColorPushButton.setEnabled(False) + + def previewTheme(self, theme): + if self.allowPreview: + frame = self.thememanager.generateImage(theme) + self.ThemePreview.setPixmap(QtGui.QPixmap.fromImage(frame)) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 001ab94b0..29002be4b 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -1,380 +1,443 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 -""" -OpenLP - Open Source Lyrics Projection -Copyright (c) 2009 Raoul Snyman -Portions copyright (c) 2009 Martin Thompson, Tim Bentley, - -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 os -import sys -import zipfile -import shutil -import logging - -from xml.etree.ElementTree import ElementTree, XML -from PyQt4 import QtCore, QtGui - -from openlp.core.ui import AmendThemeForm, ServiceManager -from openlp.core.theme import Theme -from openlp.core.lib import PluginConfig, \ - OpenLPToolbar, ThemeXML, Renderer, translate, \ - file_to_xml, buildIcon, Receiver -from openlp.core.utils import ConfigHelper - -class ThemeManager(QtGui.QWidget): - """ - Manages the orders of Theme. - """ - global log - log = logging.getLogger(u'ThemeManager') - - def __init__(self, parent): - QtGui.QWidget.__init__(self, parent) - self.parent = parent - self.Layout = QtGui.QVBoxLayout(self) - self.Layout.setSpacing(0) - self.Layout.setMargin(0) - self.amendThemeForm = AmendThemeForm(self) - self.Toolbar = OpenLPToolbar(self) - self.Toolbar.addToolbarButton( - translate(u'ThemeManager', u'New Theme'), u':/themes/theme_new.png', - translate(u'ThemeManager', u'Create a new theme'), self.onAddTheme) - self.Toolbar.addToolbarButton( - translate(u'ThemeManager', u'Edit Theme'), u':/themes/theme_edit.png', - translate(u'ThemeManager', u'Edit a theme'), self.onEditTheme) - self.Toolbar.addToolbarButton( - translate(u'ThemeManager', u'Delete Theme'), u':/themes/theme_delete.png', - translate(u'ThemeManager', u'Delete a theme'), self.onDeleteTheme) - self.Toolbar.addSeparator() - self.Toolbar.addToolbarButton( - translate(u'ThemeManager', u'Import Theme'), u':/themes/theme_import.png', - translate(u'ThemeManager', u'Import a theme'), self.onImportTheme) - self.Toolbar.addToolbarButton( - translate(u'ThemeManager', u'Export Theme'), u':/themes/theme_export.png', - translate(u'ThemeManager', u'Export a theme'), self.onExportTheme) - self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar) - self.Layout.addWidget(self.Toolbar) - self.ThemeListWidget = QtGui.QListWidget(self) - self.ThemeListWidget.setAlternatingRowColors(True) - self.ThemeListWidget.setIconSize(QtCore.QSize(88,50)) - self.Layout.addWidget(self.ThemeListWidget) - #Signals - QtCore.QObject.connect(self.ThemeListWidget, - QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.changeGlobalFromScreen) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_global_theme'), self.changeGlobalFromTab) - #Variables - self.themelist = [] - self.path = os.path.join(ConfigHelper.get_data_path(), u'themes') - self.checkThemesExists(self.path) - self.amendThemeForm.path = self.path - # Last little bits of setting up - self.config = PluginConfig(u'themes') - self.servicePath = self.config.get_data_path() - self.global_theme = unicode(self.config.get_config(u'theme global theme', u'')) - - def changeGlobalFromTab(self, themeName): - log.debug(u'changeGlobalFromTab %s', themeName) - for count in range (0, self.ThemeListWidget.count()): - #reset the old name - item = self.ThemeListWidget.item(count) - oldName = item.text() - newName = unicode(item.data(QtCore.Qt.UserRole).toString()) - if oldName != newName: - self.ThemeListWidget.item(count).setText(newName) - #Set the new name - if themeName == newName: - name = u'%s (%s)' % (newName, translate(u'ThemeManager', u'default')) - self.ThemeListWidget.item(count).setText(name) - - def changeGlobalFromScreen(self, index): - log.debug(u'changeGlobalFromScreen %s', index) - for count in range (0, self.ThemeListWidget.count()): - item = self.ThemeListWidget.item(count) - oldName = item.text() - #reset the old name - if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()): - self.ThemeListWidget.item(count).setText(unicode(item.data(QtCore.Qt.UserRole).toString())) - #Set the new name - if count == index.row(): - self.global_theme = unicode(self.ThemeListWidget.item(count).text()) - name = u'%s (%s)' % (self.global_theme, translate(u'ThemeManager', u'default')) - self.ThemeListWidget.item(count).setText(name) - self.config.set_config(u'theme global theme', self.global_theme) - Receiver().send_message(u'update_global_theme', self.global_theme ) - self.pushThemes() - - def onAddTheme(self): - self.amendThemeForm.loadTheme(None) - self.amendThemeForm.exec_() - - def onEditTheme(self): - item = self.ThemeListWidget.currentItem() - if item is not None: - self.amendThemeForm.loadTheme(unicode(item.data(QtCore.Qt.UserRole).toString())) - self.amendThemeForm.exec_() - - def onDeleteTheme(self): - self.global_theme = unicode(self.config.get_config(u'theme global theme', u'')) - item = self.ThemeListWidget.currentItem() - if item is not None: - theme = unicode(item.text()) - # should be the same unless default - if theme != unicode(item.data(QtCore.Qt.UserRole).toString()): - QtGui.QMessageBox.critical(self, - translate(u'ThemeManager', u'Error'), - translate(u'ThemeManager', u'You are unable to delete the default theme!'), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok)) - else: - self.themelist.remove(theme) - th = theme + u'.png' - row = self.ThemeListWidget.row(item) - self.ThemeListWidget.takeItem(row) - try: - os.remove(os.path.join(self.path, th)) - except: - #if not present do not worry - pass - try: - shutil.rmtree(os.path.join(self.path, theme)) - except: - #if not present do not worry - pass - #As we do not reload the themes push out the change - #Reaload the list as the internal lists and events need to be triggered - self.pushThemes() - - def onExportTheme(self): - pass - - def onImportTheme(self): - files = QtGui.QFileDialog.getOpenFileNames(None, - translate(u'ThemeManager', u'Select Theme Import File'), - self.path, u'Theme (*.*)') - log.info(u'New Themes %s', unicode(files)) - if len(files) > 0: - for file in files: - self.unzipTheme(file, self.path) - self.loadThemes() - - def loadThemes(self): - """ - Loads the theme lists and triggers updates accross - the whole system using direct calls or core functions - and events for the plugins. - The plugins will call back in to get the real list if they want it. - """ - 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, translate(u'ThemeManager', u'default')) - else: - name = textName - item_name = QtGui.QListWidgetItem(name) - item_name.setIcon(buildIcon(theme)) - item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(textName)) - self.ThemeListWidget.addItem(item_name) - self.themelist.append(textName) - self.pushThemes() - - def pushThemes(self): - Receiver().send_message(u'update_themes', self.getThemes() ) - - def getThemes(self): - return self.themelist - - def getThemeData(self, themename): - log.debug(u'getthemedata for theme %s', themename) - xml_file = os.path.join(self.path, unicode(themename), unicode(themename) + u'.xml') - try: - xml = file_to_xml(xml_file) - except: - newtheme = ThemeXML() - newtheme.new_document(u'New Theme') - newtheme.add_background_solid(unicode(u'#000000')) - newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'), unicode(30), u'False') - newtheme.add_font(unicode(QtGui.QFont().family()), unicode(u'#FFFFFF'), unicode(12), u'False', u'footer') - newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False', unicode(u'#FFFFFF'), - unicode(0), unicode(0), unicode(0)) - xml = newtheme.extract_xml() - theme = ThemeXML() - theme.parse(xml) - theme.extend_image_filename(self.path) - return theme - - def checkThemesExists(self, dir): - log.debug(u'check themes') - if os.path.exists(dir) == False: - os.mkdir(dir) - - def unzipTheme(self, filename, dir): - """ - Unzip the theme, remove the preview file if stored - Generate a new preview fileCheck the XML theme version and upgrade if - necessary. - """ - log.debug(u'Unzipping theme %s', filename) - zip = zipfile.ZipFile(unicode(filename)) - filexml = None - themename = None - for file in zip.namelist(): - if file.endswith(os.path.sep): - theme_dir = os.path.join(dir, file) - if os.path.exists(theme_dir) == False: - os.mkdir(os.path.join(dir, file)) - else: - fullpath = os.path.join(dir, file) - names = file.split(os.path.sep) - if len(names) > 1: - # not preview file - if themename is None: - themename = names[0] - xml_data = zip.read(file) - if os.path.splitext(file)[1].lower() in [u'.xml']: - if self.checkVersion1(xml_data): - # upgrade theme xml - filexml = self.migrateVersion122(filename, fullpath, xml_data) - else: - filexml = xml_data - outfile = open(fullpath, u'w') - outfile.write(filexml) - outfile.close() - else: - outfile = open(fullpath, u'w') - outfile.write(zip.read(file)) - outfile.close() - self.generateAndSaveImage(dir, themename, filexml) - - def checkVersion1(self, xmlfile): - """ - Am I a version 1 theme - """ - log.debug(u'checkVersion1 ') - theme = xmlfile - tree = ElementTree(element=XML(theme)).getroot() - if tree.find(u'BackgroundType') is None: - return False - else: - return True - - def migrateVersion122(self, filename, fullpath, xml_data): - """ - Called by convert the xml data from version 1 format - to the current format. - New fields are defaulted but the new theme is useable - """ - log.debug(u'migrateVersion122 %s %s', filename, fullpath) - theme = Theme(xml_data) - newtheme = ThemeXML() - newtheme.new_document(theme.Name) - if theme.BackgroundType == 0: - newtheme.add_background_solid(unicode(theme.BackgroundParameter1.name())) - elif theme.BackgroundType == 1: - direction = u'vertical' - if theme.BackgroundParameter3.name() == 1: - direction = u'horizontal' - newtheme.add_background_gradient( - unicode(theme.BackgroundParameter1.name()), - unicode(theme.BackgroundParameter2.name()), direction) - else: - newtheme.add_background_image(unicode(theme.BackgroundParameter1)) - - newtheme.add_font(unicode(theme.FontName), - unicode(theme.FontColor.name()), - unicode(theme.FontProportion * 2), u'False') - newtheme.add_font(unicode(theme.FontName), - unicode(theme.FontColor.name()), - unicode(12), u'False', u'footer') - outline = False - shadow = False - if theme.Shadow == 1: - shadow = True - if theme.Outline == 1: - outline = True - newtheme.add_display(unicode(shadow), unicode(theme.ShadowColor.name()), - unicode(outline), unicode(theme.OutlineColor.name()), - unicode(theme.HorizontalAlign), unicode(theme.VerticalAlign), - unicode(theme.WrapStyle)) - return newtheme.extract_xml() - - def saveTheme(self, name, theme_xml, theme_pretty_xml, image_from, - image_to) : - """ - Called by thememaintenance Dialog to save the theme - and to trigger the reload of the theme list - """ - log.debug(u'saveTheme %s %s', name, theme_xml) - theme_dir = os.path.join(self.path, name) - if os.path.exists(theme_dir) == False: - os.mkdir(os.path.join(self.path, name)) - theme_file = os.path.join(theme_dir, name + u'.xml') - log.debug(theme_file) - - result = QtGui.QMessageBox.Yes - if os.path.exists(theme_file): - result = QtGui.QMessageBox.question( - self, - translate(u'ThemeManager',u'Theme Exists'), - translate(u'ThemeManager',u'A theme with this name already exists, would you like to overwrite it?'), - (QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), - QtGui.QMessageBox.No) - if result == QtGui.QMessageBox.Yes: - # Save the theme, overwriting the existing theme if necessary. - outfile = open(theme_file, u'w') - outfile.write(theme_pretty_xml) - outfile.close() - if image_from is not None and image_from != image_to: - shutil.copyfile(image_from, image_to) - - self.generateAndSaveImage(self.path, name, theme_xml) - self.loadThemes() - else: - # Don't close the dialog - allow the user to change the name of - # the theme or to cancel the theme dialog completely. - return False - - def generateAndSaveImage(self, dir, name, theme_xml): - log.debug(u'generateAndSaveImage %s %s %s', dir, name, theme_xml) - theme = ThemeXML() - theme.parse(theme_xml) - theme.extend_image_filename(dir) - frame = self.generateImage(theme) - samplepathname = os.path.join(self.path, name + u'.png') - if os.path.exists(samplepathname): - os.unlink(samplepathname) - frame.save(samplepathname, u'png') - log.debug(u'Theme image written to %s', samplepathname) - - def generateImage(self, themedata): - """ - Call the RenderManager to build a Sample Image - """ - log.debug(u'generateImage %s ', themedata) - frame = self.parent.RenderManager.generate_preview(themedata) - return frame - - def getPreviewImage(self, theme): - log.debug(u'getPreviewImage %s ', theme) - image = os.path.join(self.path, theme + u'.png') - return image +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 +""" +OpenLP - Open Source Lyrics Projection +Copyright (c) 2009 Raoul Snyman +Portions copyright (c) 2009 Martin Thompson, Tim Bentley, + +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 os +import sys +import zipfile +import shutil +import logging + +from xml.etree.ElementTree import ElementTree, XML +from PyQt4 import QtCore, QtGui + +from openlp.core.ui import AmendThemeForm, ServiceManager +from openlp.core.theme import Theme +from openlp.core.lib import PluginConfig, OpenLPToolbar, ThemeXML, Renderer, \ + translate, str_to_bool, file_to_xml, buildIcon, Receiver +from openlp.core.utils import ConfigHelper + +class ThemeManager(QtGui.QWidget): + """ + Manages the orders of Theme. + """ + global log + log = logging.getLogger(u'ThemeManager') + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.parent = parent + self.Layout = QtGui.QVBoxLayout(self) + self.Layout.setSpacing(0) + self.Layout.setMargin(0) + self.amendThemeForm = AmendThemeForm(self) + self.Toolbar = OpenLPToolbar(self) + self.Toolbar.addToolbarButton( + translate(u'ThemeManager', u'New Theme'), u':/themes/theme_new.png', + translate(u'ThemeManager', u'Create a new theme'), self.onAddTheme) + self.Toolbar.addToolbarButton( + translate(u'ThemeManager', u'Edit Theme'), + u':/themes/theme_edit.png', + translate(u'ThemeManager', u'Edit a theme'), self.onEditTheme) + self.Toolbar.addToolbarButton( + translate(u'ThemeManager', u'Delete Theme'), + u':/themes/theme_delete.png', + translate(u'ThemeManager', u'Delete a theme'), self.onDeleteTheme) + self.Toolbar.addSeparator() + self.Toolbar.addToolbarButton( + translate(u'ThemeManager', u'Import Theme'), + u':/themes/theme_import.png', + translate(u'ThemeManager', u'Import a theme'), self.onImportTheme) + self.Toolbar.addToolbarButton( + translate(u'ThemeManager', u'Export Theme'), + u':/themes/theme_export.png', + translate(u'ThemeManager', u'Export a theme'), self.onExportTheme) + self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar) + self.Layout.addWidget(self.Toolbar) + self.ThemeListWidget = QtGui.QListWidget(self) + self.ThemeListWidget.setAlternatingRowColors(True) + self.ThemeListWidget.setIconSize(QtCore.QSize(88,50)) + self.Layout.addWidget(self.ThemeListWidget) + #Signals + QtCore.QObject.connect(self.ThemeListWidget, + QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), + self.changeGlobalFromScreen) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'update_global_theme'), self.changeGlobalFromTab) + #Variables + self.themelist = [] + self.path = os.path.join(ConfigHelper.get_data_path(), u'themes') + self.checkThemesExists(self.path) + self.amendThemeForm.path = self.path + # Last little bits of setting up + self.config = PluginConfig(u'themes') + self.servicePath = self.config.get_data_path() + self.global_theme = unicode( + self.config.get_config(u'theme global theme', u'')) + + def changeGlobalFromTab(self, themeName): + log.debug(u'changeGlobalFromTab %s', themeName) + for count in range (0, self.ThemeListWidget.count()): + #reset the old name + item = self.ThemeListWidget.item(count) + oldName = item.text() + newName = unicode(item.data(QtCore.Qt.UserRole).toString()) + if oldName != newName: + self.ThemeListWidget.item(count).setText(newName) + #Set the new name + if themeName == newName: + name = u'%s (%s)' % (newName, translate(u'ThemeManager', + u'default')) + self.ThemeListWidget.item(count).setText(name) + + def changeGlobalFromScreen(self, index): + log.debug(u'changeGlobalFromScreen %s', index) + for count in range (0, self.ThemeListWidget.count()): + item = self.ThemeListWidget.item(count) + oldName = item.text() + #reset the old name + if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()): + self.ThemeListWidget.item(count).setText( + unicode(item.data(QtCore.Qt.UserRole).toString())) + #Set the new name + if count == index.row(): + self.global_theme = unicode( + self.ThemeListWidget.item(count).text()) + name = u'%s (%s)' % (self.global_theme, + translate(u'ThemeManager', u'default')) + self.ThemeListWidget.item(count).setText(name) + self.config.set_config(u'theme global theme', self.global_theme) + Receiver().send_message(u'update_global_theme', + self.global_theme) + self.pushThemes() + + def onAddTheme(self): + self.amendThemeForm.loadTheme(None) + self.amendThemeForm.exec_() + + def onEditTheme(self): + item = self.ThemeListWidget.currentItem() + if item is not None: + self.amendThemeForm.loadTheme( + unicode(item.data(QtCore.Qt.UserRole).toString())) + self.amendThemeForm.exec_() + + def onDeleteTheme(self): + self.global_theme = unicode( + self.config.get_config(u'theme global theme', u'')) + item = self.ThemeListWidget.currentItem() + if item is not None: + theme = unicode(item.text()) + # should be the same unless default + if theme != unicode(item.data(QtCore.Qt.UserRole).toString()): + QtGui.QMessageBox.critical(self, + translate(u'ThemeManager', u'Error'), + translate(u'ThemeManager', + u'You are unable to delete the default theme!'), + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok)) + else: + self.themelist.remove(theme) + th = theme + u'.png' + row = self.ThemeListWidget.row(item) + self.ThemeListWidget.takeItem(row) + try: + os.remove(os.path.join(self.path, th)) + except: + #if not present do not worry + pass + try: + shutil.rmtree(os.path.join(self.path, theme)) + except: + #if not present do not worry + pass + # As we do not reload the themes push out the change + # Reaload the list as the internal lists and events need + # to be triggered + self.pushThemes() + + def onExportTheme(self): + pass + + def onImportTheme(self): + files = QtGui.QFileDialog.getOpenFileNames(None, + translate(u'ThemeManager', u'Select Theme Import File'), + self.path, u'Theme (*.*)') + log.info(u'New Themes %s', unicode(files)) + if len(files) > 0: + for file in files: + self.unzipTheme(file, self.path) + self.loadThemes() + + def loadThemes(self): + """ + Loads the theme lists and triggers updates accross + the whole system using direct calls or core functions + and events for the plugins. + The plugins will call back in to get the real list if they want it. + """ + 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, + translate(u'ThemeManager', u'default')) + else: + name = textName + item_name = QtGui.QListWidgetItem(name) + item_name.setIcon(buildIcon(theme)) + item_name.setData(QtCore.Qt.UserRole, + QtCore.QVariant(textName)) + self.ThemeListWidget.addItem(item_name) + self.themelist.append(textName) + self.pushThemes() + + def pushThemes(self): + Receiver().send_message(u'update_themes', self.getThemes() ) + + def getThemes(self): + return self.themelist + + def getThemeData(self, themename): + log.debug(u'getthemedata for theme %s', themename) + xml_file = os.path.join(self.path, unicode(themename), + unicode(themename) + u'.xml') + try: + xml = file_to_xml(xml_file) + except: + newtheme = ThemeXML() + newtheme.new_document(u'New Theme') + newtheme.add_background_solid(unicode(u'#000000')) + newtheme.add_font(unicode(QtGui.QFont().family()), + unicode(u'#FFFFFF'), unicode(30), u'False') + newtheme.add_font(unicode(QtGui.QFont().family()), + unicode(u'#FFFFFF'), unicode(12), u'False', u'footer') + newtheme.add_display(u'False', unicode(u'#FFFFFF'), u'False', + unicode(u'#FFFFFF'), unicode(0), unicode(0), unicode(0)) + xml = newtheme.extract_xml() + theme = ThemeXML() + theme.parse(xml) + theme.extend_image_filename(self.path) + self.cleanTheme(theme) + return theme + + def checkThemesExists(self, dir): + log.debug(u'check themes') + if os.path.exists(dir) == False: + os.mkdir(dir) + + def unzipTheme(self, filename, dir): + """ + Unzip the theme, remove the preview file if stored + Generate a new preview fileCheck the XML theme version and upgrade if + necessary. + """ + log.debug(u'Unzipping theme %s', filename) + zip = zipfile.ZipFile(unicode(filename)) + filexml = None + themename = None + for file in zip.namelist(): + if file.endswith(os.path.sep): + theme_dir = os.path.join(dir, file) + if os.path.exists(theme_dir) == False: + os.mkdir(os.path.join(dir, file)) + else: + fullpath = os.path.join(dir, file) + names = file.split(os.path.sep) + if len(names) > 1: + # not preview file + if themename is None: + themename = names[0] + xml_data = zip.read(file) + if os.path.splitext(file)[1].lower() in [u'.xml']: + if self.checkVersion1(xml_data): + # upgrade theme xml + filexml = self.migrateVersion122(filename, + fullpath, xml_data) + else: + filexml = xml_data + outfile = open(fullpath, u'w') + outfile.write(filexml) + outfile.close() + else: + outfile = open(fullpath, u'w') + outfile.write(zip.read(file)) + outfile.close() + self.generateAndSaveImage(dir, themename, filexml) + + def checkVersion1(self, xmlfile): + """ + Am I a version 1 theme + """ + log.debug(u'checkVersion1 ') + theme = xmlfile + tree = ElementTree(element=XML(theme)).getroot() + if tree.find(u'BackgroundType') is None: + return False + else: + return True + + def migrateVersion122(self, filename, fullpath, xml_data): + """ + Called by convert the xml data from version 1 format + to the current format. + New fields are defaulted but the new theme is useable + """ + log.debug(u'migrateVersion122 %s %s', filename, fullpath) + theme = Theme(xml_data) + newtheme = ThemeXML() + newtheme.new_document(theme.Name) + if theme.BackgroundType == 0: + newtheme.add_background_solid(unicode( + theme.BackgroundParameter1.name())) + elif theme.BackgroundType == 1: + direction = u'vertical' + if theme.BackgroundParameter3.name() == 1: + direction = u'horizontal' + newtheme.add_background_gradient( + unicode(theme.BackgroundParameter1.name()), + unicode(theme.BackgroundParameter2.name()), direction) + else: + newtheme.add_background_image(unicode(theme.BackgroundParameter1)) + + newtheme.add_font(unicode(theme.FontName), + unicode(theme.FontColor.name()), + unicode(theme.FontProportion * 2), u'False') + newtheme.add_font(unicode(theme.FontName), + unicode(theme.FontColor.name()), + unicode(12), u'False', u'footer') + outline = False + shadow = False + if theme.Shadow == 1: + shadow = True + if theme.Outline == 1: + outline = True + newtheme.add_display(unicode(shadow), unicode(theme.ShadowColor.name()), + unicode(outline), unicode(theme.OutlineColor.name()), + unicode(theme.HorizontalAlign), unicode(theme.VerticalAlign), + unicode(theme.WrapStyle)) + return newtheme.extract_xml() + + def saveTheme(self, name, theme_xml, theme_pretty_xml, image_from, + image_to) : + """ + Called by thememaintenance Dialog to save the theme + and to trigger the reload of the theme list + """ + log.debug(u'saveTheme %s %s', name, theme_xml) + theme_dir = os.path.join(self.path, name) + if os.path.exists(theme_dir) == False: + os.mkdir(os.path.join(self.path, name)) + theme_file = os.path.join(theme_dir, name + u'.xml') + log.debug(theme_file) + + result = QtGui.QMessageBox.Yes + if os.path.exists(theme_file): + result = QtGui.QMessageBox.question( + self, + translate(u'ThemeManager', u'Theme Exists'), + translate(u'ThemeManager', u'A theme with this name already exists, would you like to overwrite it?'), + (QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if result == QtGui.QMessageBox.Yes: + # Save the theme, overwriting the existing theme if necessary. + outfile = open(theme_file, u'w') + outfile.write(theme_pretty_xml) + outfile.close() + if image_from is not None and image_from != image_to: + shutil.copyfile(image_from, image_to) + + self.generateAndSaveImage(self.path, name, theme_xml) + self.loadThemes() + else: + # Don't close the dialog - allow the user to change the name of + # the theme or to cancel the theme dialog completely. + return False + + def generateAndSaveImage(self, dir, name, theme_xml): + log.debug(u'generateAndSaveImage %s %s %s', dir, name, theme_xml) + theme = ThemeXML() + theme.parse(theme_xml) + theme.extend_image_filename(dir) + frame = self.generateImage(theme) + samplepathname = os.path.join(self.path, name + u'.png') + if os.path.exists(samplepathname): + os.unlink(samplepathname) + frame.save(samplepathname, u'png') + log.debug(u'Theme image written to %s', samplepathname) + + def generateImage(self, themedata): + """ + Call the RenderManager to build a Sample Image + """ + log.debug(u'generateImage %s ', themedata) + frame = self.parent.RenderManager.generate_preview(themedata) + return frame + + def getPreviewImage(self, theme): + log.debug(u'getPreviewImage %s ', theme) + image = os.path.join(self.path, theme + u'.png') + return image + + def cleanTheme(self, theme): + theme.background_color = theme.background_color.strip() + theme.background_direction = theme.background_direction.strip() + theme.background_endColor = theme.background_endColor.strip() + if theme.background_filename: + theme.background_filename = theme.background_filename.strip() + #theme.background_mode + theme.background_startColor = theme.background_startColor.strip() + #theme.background_type + if theme.display_display: + theme.display_display = theme.display_display.strip() + theme.display_horizontalAlign = theme.display_horizontalAlign.strip() + theme.display_outline = str_to_bool(theme.display_outline) + #theme.display_outline_color + theme.display_shadow = str_to_bool(theme.display_shadow) + #theme.display_shadow_color + theme.display_verticalAlign = theme.display_verticalAlign.strip() + theme.display_wrapStyle = theme.display_wrapStyle.strip() + theme.font_footer_color = theme.font_footer_color.strip() + theme.font_footer_height = theme.font_footer_height.strip() + theme.font_footer_italics = str_to_bool(theme.font_footer_italics) + theme.font_footer_name = theme.font_footer_name.strip() + #theme.font_footer_override + theme.font_footer_proportion = theme.font_footer_proportion.strip() + theme.font_footer_weight = theme.font_footer_weight.strip() + theme.font_footer_width = theme.font_footer_width.strip() + theme.font_footer_x = theme.font_footer_x.strip() + theme.font_footer_y = theme.font_footer_y.strip() + theme.font_main_color = theme.font_main_color.strip() + theme.font_main_height = theme.font_main_height.strip() + theme.font_main_italics = str_to_bool(theme.font_main_italics) + theme.font_main_name = theme.font_main_name.strip() + #theme.font_main_override + theme.font_main_proportion = theme.font_main_proportion.strip() + theme.font_main_weight = theme.font_main_weight.strip() + theme.font_main_x = theme.font_main_x.strip() + theme.font_main_y = theme.font_main_y.strip() + #theme.theme_mode + theme.theme_name = theme.theme_name.strip() + #theme.theme_version