2009-09-13 15:14:45 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2012-12-29 15:25:29 +00:00
|
|
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2019-04-13 13:00:22 +00:00
|
|
|
##########################################################################
|
|
|
|
# OpenLP - Open Source Lyrics Projection #
|
|
|
|
# ---------------------------------------------------------------------- #
|
|
|
|
# Copyright (c) 2008-2019 OpenLP Developers #
|
|
|
|
# ---------------------------------------------------------------------- #
|
|
|
|
# This program is free software: you can redistribute it and/or modify #
|
|
|
|
# it under the terms of the GNU General Public License as published by #
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or #
|
|
|
|
# (at your option) any later version. #
|
|
|
|
# #
|
|
|
|
# This program is distributed in the hope that it will be useful, #
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
|
|
# GNU General Public License for more details. #
|
|
|
|
# #
|
|
|
|
# You should have received a copy of the GNU General Public License #
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
|
|
|
##########################################################################
|
2013-02-01 21:34:23 +00:00
|
|
|
"""
|
|
|
|
The Theme Manager manages adding, deleteing and modifying of themes.
|
|
|
|
"""
|
2009-09-13 15:14:45 +00:00
|
|
|
import os
|
2019-05-22 06:47:00 +00:00
|
|
|
import shutil
|
2009-09-13 15:14:45 +00:00
|
|
|
import zipfile
|
2019-05-22 06:47:00 +00:00
|
|
|
from pathlib import Path
|
2018-10-02 04:39:42 +00:00
|
|
|
from xml.etree.ElementTree import XML, ElementTree
|
2017-09-26 16:39:13 +00:00
|
|
|
|
2019-04-21 12:48:23 +00:00
|
|
|
from PyQt5 import QtCore, QtWidgets
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2019-07-31 21:01:22 +00:00
|
|
|
from openlp.core.state import State
|
2017-10-07 07:05:07 +00:00
|
|
|
from openlp.core.common import delete_file
|
|
|
|
from openlp.core.common.applocation import AppLocation
|
2018-10-02 04:39:42 +00:00
|
|
|
from openlp.core.common.i18n import UiStrings, get_locale_key, translate
|
2017-10-23 22:09:57 +00:00
|
|
|
from openlp.core.common.mixins import LogMixin, RegistryProperties
|
2019-05-22 06:47:00 +00:00
|
|
|
from openlp.core.common.path import create_paths
|
2017-10-23 22:09:57 +00:00
|
|
|
from openlp.core.common.registry import Registry, RegistryBase
|
2017-10-07 07:05:07 +00:00
|
|
|
from openlp.core.common.settings import Settings
|
2019-04-21 12:48:23 +00:00
|
|
|
from openlp.core.lib import build_icon, check_item_selected, create_thumb, get_text_file_string, validate_thumb
|
2018-08-25 14:08:19 +00:00
|
|
|
from openlp.core.lib.exceptions import ValidationError
|
2019-04-21 12:48:23 +00:00
|
|
|
from openlp.core.lib.theme import Theme
|
2018-10-02 04:39:42 +00:00
|
|
|
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
|
2018-08-25 14:08:19 +00:00
|
|
|
from openlp.core.ui.filerenameform import FileRenameForm
|
2018-10-02 04:39:42 +00:00
|
|
|
from openlp.core.ui.icons import UiIcons
|
2018-08-25 14:08:19 +00:00
|
|
|
from openlp.core.ui.themeform import ThemeForm
|
2017-10-23 22:09:57 +00:00
|
|
|
from openlp.core.widgets.dialogs import FileDialog
|
|
|
|
from openlp.core.widgets.toolbar import OpenLPToolbar
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2010-02-27 15:31:23 +00:00
|
|
|
|
2013-12-31 20:29:03 +00:00
|
|
|
class Ui_ThemeManager(object):
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2013-12-31 20:29:03 +00:00
|
|
|
UI part of the Theme Manager
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2013-12-31 20:29:03 +00:00
|
|
|
def setup_ui(self, widget):
|
2013-02-01 21:34:23 +00:00
|
|
|
"""
|
2013-12-31 20:29:03 +00:00
|
|
|
Define the UI
|
2014-01-01 09:33:07 +00:00
|
|
|
:param widget: The screen object the the dialog is to be attached to.
|
2013-02-01 21:34:23 +00:00
|
|
|
"""
|
2011-01-02 22:24:14 +00:00
|
|
|
# start with the layout
|
2015-11-07 00:49:40 +00:00
|
|
|
self.layout = QtWidgets.QVBoxLayout(widget)
|
2010-07-27 12:18:10 +00:00
|
|
|
self.layout.setSpacing(0)
|
2015-11-07 00:49:40 +00:00
|
|
|
self.layout.setContentsMargins(0, 0, 0, 0)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.layout.setObjectName('layout')
|
2013-12-31 21:02:35 +00:00
|
|
|
self.toolbar = OpenLPToolbar(widget)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.toolbar.setObjectName('toolbar')
|
|
|
|
self.toolbar.add_toolbar_action('newTheme',
|
2018-04-07 20:31:54 +00:00
|
|
|
text=UiStrings().NewTheme, icon=UiIcons().new,
|
2013-12-23 07:03:56 +00:00
|
|
|
tooltip=translate('OpenLP.ThemeManager', 'Create a new theme.'),
|
|
|
|
triggers=self.on_add_theme)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.toolbar.add_toolbar_action('editTheme',
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', 'Edit Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().edit,
|
2013-12-23 07:03:56 +00:00
|
|
|
tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'),
|
|
|
|
triggers=self.on_edit_theme)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.delete_toolbar_action = self.toolbar.add_toolbar_action('delete_theme',
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager',
|
|
|
|
'Delete Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().delete,
|
2013-12-23 07:03:56 +00:00
|
|
|
tooltip=translate('OpenLP.ThemeManager',
|
|
|
|
'Delete a theme.'),
|
|
|
|
triggers=self.on_delete_theme)
|
2012-03-02 10:22:52 +00:00
|
|
|
self.toolbar.addSeparator()
|
2013-08-31 18:17:38 +00:00
|
|
|
self.toolbar.add_toolbar_action('importTheme',
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', 'Import Theme'),
|
2018-04-21 05:47:20 +00:00
|
|
|
icon=UiIcons().download,
|
2013-12-23 07:03:56 +00:00
|
|
|
tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'),
|
|
|
|
triggers=self.on_import_theme)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.toolbar.add_toolbar_action('exportTheme',
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', 'Export Theme'),
|
2018-04-21 05:47:20 +00:00
|
|
|
icon=UiIcons().upload,
|
2013-12-23 07:03:56 +00:00
|
|
|
tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'),
|
|
|
|
triggers=self.on_export_theme)
|
2010-07-27 12:18:10 +00:00
|
|
|
self.layout.addWidget(self.toolbar)
|
2015-11-07 00:49:40 +00:00
|
|
|
self.theme_widget = QtWidgets.QWidgetAction(self.toolbar)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.theme_widget.setObjectName('theme_widget')
|
2011-01-02 22:24:14 +00:00
|
|
|
# create theme manager list
|
2015-11-07 00:49:40 +00:00
|
|
|
self.theme_list_widget = QtWidgets.QListWidget(widget)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list_widget.setAlternatingRowColors(True)
|
|
|
|
self.theme_list_widget.setIconSize(QtCore.QSize(88, 50))
|
|
|
|
self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
2013-08-31 18:17:38 +00:00
|
|
|
self.theme_list_widget.setObjectName('theme_list_widget')
|
2013-02-01 21:48:06 +00:00
|
|
|
self.layout.addWidget(self.theme_list_widget)
|
2013-02-14 21:50:10 +00:00
|
|
|
self.theme_list_widget.customContextMenuRequested.connect(self.context_menu)
|
2010-09-26 08:07:47 +00:00
|
|
|
# build the context menu
|
2015-11-07 00:49:40 +00:00
|
|
|
self.menu = QtWidgets.QMenu()
|
2013-02-01 21:48:06 +00:00
|
|
|
self.edit_action = create_widget_action(self.menu,
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', '&Edit Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().edit, triggers=self.on_edit_theme)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.copy_action = create_widget_action(self.menu,
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', '&Copy Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().copy, triggers=self.on_copy_theme)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.rename_action = create_widget_action(self.menu,
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', '&Rename Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().edit, triggers=self.on_rename_theme)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.delete_action = create_widget_action(self.menu,
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', '&Delete Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().delete, triggers=self.on_delete_theme)
|
2012-03-02 10:22:52 +00:00
|
|
|
self.menu.addSeparator()
|
2013-02-01 21:48:06 +00:00
|
|
|
self.global_action = create_widget_action(self.menu,
|
2013-12-23 07:03:56 +00:00
|
|
|
text=translate('OpenLP.ThemeManager', 'Set As &Global Default'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().default,
|
2013-12-23 07:03:56 +00:00
|
|
|
triggers=self.change_global_from_screen)
|
2013-12-24 06:15:41 +00:00
|
|
|
self.export_action = create_widget_action(self.menu,
|
|
|
|
text=translate('OpenLP.ThemeManager', '&Export Theme'),
|
2018-04-07 20:31:54 +00:00
|
|
|
icon=UiIcons().upload, triggers=self.on_export_theme)
|
2010-12-27 10:18:09 +00:00
|
|
|
# Signals
|
2013-02-14 21:50:10 +00:00
|
|
|
self.theme_list_widget.doubleClicked.connect(self.change_global_from_screen)
|
|
|
|
self.theme_list_widget.currentItemChanged.connect(self.check_list_state)
|
2013-12-31 20:29:03 +00:00
|
|
|
|
|
|
|
|
2017-10-23 22:09:57 +00:00
|
|
|
class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, RegistryProperties):
|
2013-12-31 20:29:03 +00:00
|
|
|
"""
|
|
|
|
Manages the orders of Theme.
|
|
|
|
"""
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
"""
|
|
|
|
Constructor
|
|
|
|
"""
|
|
|
|
super(ThemeManager, self).__init__(parent)
|
|
|
|
self.settings_section = 'themes'
|
2010-12-27 10:18:09 +00:00
|
|
|
# Variables
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list = []
|
2017-09-26 16:39:13 +00:00
|
|
|
self.old_background_image_path = None
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def bootstrap_initialise(self):
|
|
|
|
"""
|
|
|
|
process the bootstrap initialise setup request
|
|
|
|
"""
|
2013-12-31 20:29:03 +00:00
|
|
|
self.setup_ui(self)
|
2013-12-23 07:03:56 +00:00
|
|
|
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
|
|
|
self.build_theme_path()
|
|
|
|
self.load_first_time_themes()
|
2019-03-03 09:49:01 +00:00
|
|
|
self.upgrade_themes() # TODO: Can be removed when upgrade path from OpenLP 2.4 no longer needed
|
2013-12-23 07:03:56 +00:00
|
|
|
|
|
|
|
def bootstrap_post_set_up(self):
|
|
|
|
"""
|
|
|
|
process the bootstrap post setup request
|
|
|
|
"""
|
2013-12-31 20:29:03 +00:00
|
|
|
self.theme_form = ThemeForm(self)
|
2017-09-26 16:39:13 +00:00
|
|
|
self.theme_form.path = self.theme_path
|
2013-12-31 20:29:03 +00:00
|
|
|
self.file_rename_form = FileRenameForm()
|
|
|
|
Registry().register_function('theme_update_global', self.change_global_from_tab)
|
2014-01-04 20:58:18 +00:00
|
|
|
self.load_themes()
|
2013-12-23 07:03:56 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def upgrade_themes(self):
|
|
|
|
"""
|
|
|
|
Upgrade the xml files to json.
|
|
|
|
|
|
|
|
:rtype: None
|
|
|
|
"""
|
|
|
|
xml_file_paths = AppLocation.get_section_data_path('themes').glob('*/*.xml')
|
|
|
|
for xml_file_path in xml_file_paths:
|
|
|
|
theme_data = get_text_file_string(xml_file_path)
|
|
|
|
theme = self._create_theme_from_xml(theme_data, self.theme_path)
|
2019-06-11 19:11:54 +00:00
|
|
|
self.save_theme(theme)
|
2017-09-26 16:39:13 +00:00
|
|
|
xml_file_path.unlink()
|
|
|
|
|
2013-12-31 20:29:03 +00:00
|
|
|
def build_theme_path(self):
|
|
|
|
"""
|
|
|
|
Set up the theme path variables
|
2017-09-26 16:39:13 +00:00
|
|
|
|
|
|
|
:rtype: None
|
2013-12-31 20:29:03 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
self.theme_path = AppLocation.get_section_data_path(self.settings_section)
|
|
|
|
self.thumb_path = self.theme_path / 'thumbnails'
|
2017-10-07 07:05:07 +00:00
|
|
|
create_paths(self.theme_path, self.thumb_path)
|
2013-12-31 20:29:03 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def check_list_state(self, item, field=None):
|
2011-01-10 17:40:47 +00:00
|
|
|
"""
|
|
|
|
If Default theme selected remove delete button.
|
2013-12-23 07:03:56 +00:00
|
|
|
Note for some reason a dummy field is required. Nothing is passed!
|
2014-01-01 09:33:07 +00:00
|
|
|
|
|
|
|
:param field:
|
|
|
|
:param item: Service Item to process
|
2011-01-10 17:40:47 +00:00
|
|
|
"""
|
2011-05-03 17:05:17 +00:00
|
|
|
if item is None:
|
|
|
|
return
|
2012-05-19 15:10:05 +00:00
|
|
|
real_theme_name = item.data(QtCore.Qt.UserRole)
|
2012-05-17 18:57:01 +00:00
|
|
|
theme_name = item.text()
|
2011-01-11 17:44:13 +00:00
|
|
|
# If default theme restrict actions
|
2012-03-10 16:03:58 +00:00
|
|
|
if real_theme_name == theme_name:
|
2013-03-16 11:05:52 +00:00
|
|
|
self.delete_toolbar_action.setVisible(True)
|
2011-01-10 17:40:47 +00:00
|
|
|
else:
|
2013-03-16 11:05:52 +00:00
|
|
|
self.delete_toolbar_action.setVisible(False)
|
2011-01-10 17:40:47 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def context_menu(self, point):
|
2010-12-28 10:56:19 +00:00
|
|
|
"""
|
2014-01-01 09:33:07 +00:00
|
|
|
Build the Right Click Context menu and set state depending on the type of theme.
|
|
|
|
|
|
|
|
:param point: The position of the mouse so the correct item can be found.
|
2010-12-28 10:56:19 +00:00
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.itemAt(point)
|
2010-09-26 08:07:47 +00:00
|
|
|
if item is None:
|
|
|
|
return
|
2012-05-19 15:10:05 +00:00
|
|
|
real_theme_name = item.data(QtCore.Qt.UserRole)
|
2013-08-31 18:17:38 +00:00
|
|
|
theme_name = str(item.text())
|
2012-06-27 17:00:02 +00:00
|
|
|
visible = real_theme_name == theme_name
|
2013-02-01 21:48:06 +00:00
|
|
|
self.delete_action.setVisible(visible)
|
|
|
|
self.rename_action.setVisible(visible)
|
|
|
|
self.global_action.setVisible(visible)
|
2015-11-07 00:49:40 +00:00
|
|
|
self.menu.exec(self.theme_list_widget.mapToGlobal(point))
|
2010-09-26 08:07:47 +00:00
|
|
|
|
2013-03-11 19:11:46 +00:00
|
|
|
def change_global_from_tab(self):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2013-03-10 20:19:42 +00:00
|
|
|
Change the global theme when it is changed through the Themes settings tab
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2013-08-31 18:17:38 +00:00
|
|
|
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
2016-05-20 16:22:06 +00:00
|
|
|
self.log_debug('change_global_from_tab {text}'.format(text=self.global_theme))
|
2013-02-02 21:16:42 +00:00
|
|
|
for count in range(0, self.theme_list_widget.count()):
|
2010-08-28 15:49:51 +00:00
|
|
|
# reset the old name
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.item(count)
|
2012-03-10 16:03:58 +00:00
|
|
|
old_name = item.text()
|
2012-05-19 15:10:05 +00:00
|
|
|
new_name = item.data(QtCore.Qt.UserRole)
|
2012-03-10 16:03:58 +00:00
|
|
|
if old_name != new_name:
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list_widget.item(count).setText(new_name)
|
2010-08-28 15:49:51 +00:00
|
|
|
# Set the new name
|
2013-03-11 19:11:46 +00:00
|
|
|
if self.global_theme == new_name:
|
2016-05-20 16:22:06 +00:00
|
|
|
name = translate('OpenLP.ThemeManager', '{text} (default)').format(text=new_name)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list_widget.item(count).setText(name)
|
2013-03-16 11:05:52 +00:00
|
|
|
self.delete_toolbar_action.setVisible(item not in self.theme_list_widget.selectedItems())
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-05 21:42:15 +00:00
|
|
|
def change_global_from_screen(self, index=-1):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2014-01-01 09:33:07 +00:00
|
|
|
Change the global theme when a theme is double clicked upon in the Theme Manager list.
|
|
|
|
|
|
|
|
:param index:
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
selected_row = self.theme_list_widget.currentRow()
|
2013-02-02 21:16:42 +00:00
|
|
|
for count in range(0, self.theme_list_widget.count()):
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.item(count)
|
2012-03-10 16:03:58 +00:00
|
|
|
old_name = item.text()
|
2010-08-28 15:49:51 +00:00
|
|
|
# reset the old name
|
2012-05-19 15:10:05 +00:00
|
|
|
if old_name != item.data(QtCore.Qt.UserRole):
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list_widget.item(count).setText(item.data(QtCore.Qt.UserRole))
|
2010-08-28 15:49:51 +00:00
|
|
|
# Set the new name
|
2009-10-10 18:36:58 +00:00
|
|
|
if count == selected_row:
|
2013-02-01 21:48:06 +00:00
|
|
|
self.global_theme = self.theme_list_widget.item(count).text()
|
2016-05-20 16:22:06 +00:00
|
|
|
name = translate('OpenLP.ThemeManager', '{text} (default)').format(text=self.global_theme)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list_widget.item(count).setText(name)
|
2013-08-31 18:17:38 +00:00
|
|
|
Settings().setValue(self.settings_section + '/global theme', self.global_theme)
|
|
|
|
Registry().execute('theme_update_global')
|
2013-02-01 21:48:06 +00:00
|
|
|
self._push_themes()
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def on_add_theme(self, field=None):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2014-01-01 09:33:07 +00:00
|
|
|
Loads a new theme with the default settings and then launches the theme editing form for the user to make
|
|
|
|
their customisations.
|
|
|
|
:param field:
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2017-05-13 07:47:22 +00:00
|
|
|
theme = Theme()
|
2012-05-20 14:05:06 +00:00
|
|
|
theme.set_default_header_footer()
|
2013-03-16 11:05:52 +00:00
|
|
|
self.theme_form.theme = theme
|
2015-11-07 00:49:40 +00:00
|
|
|
self.theme_form.exec()
|
2013-02-01 21:48:06 +00:00
|
|
|
self.load_themes()
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def on_rename_theme(self, field=None):
|
2010-09-26 06:20:24 +00:00
|
|
|
"""
|
|
|
|
Renames an existing theme to a new name
|
2014-01-01 09:33:07 +00:00
|
|
|
:param field:
|
2010-09-26 06:20:24 +00:00
|
|
|
"""
|
2012-12-29 15:25:29 +00:00
|
|
|
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
|
2013-12-23 07:03:56 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'Rename Confirmation'),
|
2017-05-30 18:42:35 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'Rename {theme_name} theme?'), False, False):
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.currentItem()
|
2012-05-19 15:10:05 +00:00
|
|
|
old_theme_name = item.data(QtCore.Qt.UserRole)
|
2013-03-16 11:05:52 +00:00
|
|
|
self.file_rename_form.file_name_edit.setText(old_theme_name)
|
2015-11-07 00:49:40 +00:00
|
|
|
if self.file_rename_form.exec():
|
2013-03-16 11:05:52 +00:00
|
|
|
new_theme_name = self.file_rename_form.file_name_edit.text()
|
2012-03-10 16:03:58 +00:00
|
|
|
if old_theme_name == new_theme_name:
|
2011-04-17 12:36:35 +00:00
|
|
|
return
|
2013-02-01 21:48:06 +00:00
|
|
|
if self.check_if_theme_exists(new_theme_name):
|
|
|
|
old_theme_data = self.get_theme_data(old_theme_name)
|
2013-03-16 11:05:52 +00:00
|
|
|
self.clone_theme_data(old_theme_data, new_theme_name)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.delete_theme(old_theme_name)
|
2019-07-31 21:01:22 +00:00
|
|
|
for plugin in State().list_plugins():
|
2013-02-19 21:23:56 +00:00
|
|
|
if plugin.uses_theme(old_theme_name):
|
|
|
|
plugin.rename_theme(old_theme_name, new_theme_name)
|
2019-02-13 21:19:24 +00:00
|
|
|
self.renderer.set_theme(self.get_theme_data(new_theme_name))
|
2013-02-01 21:48:06 +00:00
|
|
|
self.load_themes()
|
2010-09-26 06:20:24 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def on_copy_theme(self, field=None):
|
2010-09-26 06:20:24 +00:00
|
|
|
"""
|
|
|
|
Copies an existing theme to a new name
|
2014-01-01 09:33:07 +00:00
|
|
|
:param field:
|
2010-09-26 06:20:24 +00:00
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.currentItem()
|
2012-05-19 15:10:05 +00:00
|
|
|
old_theme_name = item.data(QtCore.Qt.UserRole)
|
2013-03-16 11:05:52 +00:00
|
|
|
self.file_rename_form.file_name_edit.setText(translate('OpenLP.ThemeManager',
|
2016-05-20 16:22:06 +00:00
|
|
|
'Copy of {name}',
|
|
|
|
'Copy of <theme name>').format(name=old_theme_name))
|
2015-11-07 00:49:40 +00:00
|
|
|
if self.file_rename_form.exec(True):
|
2013-03-16 11:05:52 +00:00
|
|
|
new_theme_name = self.file_rename_form.file_name_edit.text()
|
2013-02-01 21:48:06 +00:00
|
|
|
if self.check_if_theme_exists(new_theme_name):
|
|
|
|
theme_data = self.get_theme_data(old_theme_name)
|
2013-03-16 11:05:52 +00:00
|
|
|
self.clone_theme_data(theme_data, new_theme_name)
|
2010-09-26 07:39:50 +00:00
|
|
|
|
2013-03-16 11:05:52 +00:00
|
|
|
def clone_theme_data(self, theme_data, new_theme_name):
|
2010-09-26 07:39:50 +00:00
|
|
|
"""
|
2010-10-03 07:42:02 +00:00
|
|
|
Takes a theme and makes a new copy of it as well as saving it.
|
2014-01-01 09:33:07 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
:param Theme theme_data: The theme to be used
|
|
|
|
:param str new_theme_name: The new theme name of the theme
|
|
|
|
:rtype: None
|
2010-09-26 07:39:50 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
destination_path = None
|
|
|
|
source_path = None
|
2016-04-30 15:40:23 +00:00
|
|
|
if theme_data.background_type == 'image' or theme_data.background_type == 'video':
|
2017-09-26 16:39:13 +00:00
|
|
|
destination_path = self.theme_path / new_theme_name / theme_data.background_filename.name
|
|
|
|
source_path = theme_data.background_filename
|
2012-03-10 16:03:58 +00:00
|
|
|
theme_data.theme_name = new_theme_name
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_data.extend_image_filename(self.theme_path)
|
|
|
|
self.save_theme(theme_data, source_path, destination_path)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.load_themes()
|
2010-09-26 06:20:24 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def on_edit_theme(self, field=None):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
|
|
|
Loads the settings for the theme that is to be edited and launches the
|
|
|
|
theme editing form so the user can make their changes.
|
2014-01-01 09:33:07 +00:00
|
|
|
:param field:
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
if check_item_selected(self.theme_list_widget,
|
2013-12-23 07:03:56 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'You must select a theme to edit.')):
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.currentItem()
|
|
|
|
theme = self.get_theme_data(item.data(QtCore.Qt.UserRole))
|
2016-04-30 15:40:23 +00:00
|
|
|
if theme.background_type == 'image' or theme.background_type == 'video':
|
2017-09-26 16:39:13 +00:00
|
|
|
self.old_background_image_path = theme.background_filename
|
2013-03-16 11:05:52 +00:00
|
|
|
self.theme_form.theme = theme
|
2015-11-07 00:49:40 +00:00
|
|
|
self.theme_form.exec(True)
|
2017-09-26 16:39:13 +00:00
|
|
|
self.old_background_image_path = None
|
2019-02-13 20:54:35 +00:00
|
|
|
self.renderer.set_theme(theme)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.load_themes()
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-12-23 07:03:56 +00:00
|
|
|
def on_delete_theme(self, field=None):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2014-01-01 09:33:07 +00:00
|
|
|
Delete a theme triggered by the UI.
|
|
|
|
:param field:
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2012-12-29 15:25:29 +00:00
|
|
|
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
|
2013-12-30 19:50:34 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'Delete Confirmation'),
|
2017-05-30 18:42:35 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'Delete {theme_name} theme?')):
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.currentItem()
|
2012-05-17 18:57:01 +00:00
|
|
|
theme = item.text()
|
2013-02-01 21:48:06 +00:00
|
|
|
row = self.theme_list_widget.row(item)
|
|
|
|
self.theme_list_widget.takeItem(row)
|
|
|
|
self.delete_theme(theme)
|
2019-02-13 20:54:35 +00:00
|
|
|
self.renderer.set_theme(item.data(QtCore.Qt.UserRole))
|
2011-02-05 20:10:08 +00:00
|
|
|
# As we do not reload the themes, push out the change. Reload the
|
|
|
|
# list as the internal lists and events need to be triggered.
|
2013-02-01 21:48:06 +00:00
|
|
|
self._push_themes()
|
2010-07-12 21:11:00 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def delete_theme(self, theme):
|
2010-07-12 21:11:00 +00:00
|
|
|
"""
|
|
|
|
Delete a theme.
|
|
|
|
|
2014-01-01 09:33:07 +00:00
|
|
|
:param theme: The theme to delete.
|
2010-07-12 21:11:00 +00:00
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list.remove(theme)
|
2016-05-20 16:22:06 +00:00
|
|
|
thumb = '{name}.png'.format(name=theme)
|
2017-09-26 16:39:13 +00:00
|
|
|
delete_file(self.theme_path / thumb)
|
|
|
|
delete_file(self.thumb_path / thumb)
|
2010-07-12 21:11:00 +00:00
|
|
|
try:
|
2019-05-22 06:47:00 +00:00
|
|
|
shutil.rmtree(self.theme_path / theme)
|
2017-09-26 16:39:13 +00:00
|
|
|
except OSError:
|
2016-05-20 16:22:06 +00:00
|
|
|
self.log_exception('Error deleting theme {name}'.format(name=theme))
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def on_export_theme(self, checked=None):
|
2009-09-14 18:53:56 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
Export the theme to a zip file
|
|
|
|
|
|
|
|
:param bool checked: Sent by the QAction.triggered signal. It's not used in this method.
|
|
|
|
:rtype: None
|
2009-09-14 18:53:56 +00:00
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
item = self.theme_list_widget.currentItem()
|
2009-09-14 18:53:56 +00:00
|
|
|
if item is None:
|
2012-12-29 15:25:29 +00:00
|
|
|
critical_error_message_box(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.'))
|
2009-09-14 18:53:56 +00:00
|
|
|
return
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_name = item.data(QtCore.Qt.UserRole)
|
2017-08-26 15:06:11 +00:00
|
|
|
export_path, filter_used = \
|
|
|
|
FileDialog.getSaveFileName(self.main_window,
|
2017-09-26 17:02:56 +00:00
|
|
|
translate('OpenLP.ThemeManager',
|
|
|
|
'Save Theme - ({name})').format(name=theme_name),
|
|
|
|
Settings().value(self.settings_section + '/last directory export'),
|
|
|
|
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'),
|
|
|
|
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
|
2013-02-03 19:23:12 +00:00
|
|
|
self.application.set_busy_cursor()
|
2017-08-26 15:06:11 +00:00
|
|
|
if export_path:
|
|
|
|
Settings().setValue(self.settings_section + '/last directory export', export_path.parent)
|
2017-09-26 16:39:13 +00:00
|
|
|
if self._export_theme(export_path.with_suffix('.otz'), theme_name):
|
2015-11-07 00:49:40 +00:00
|
|
|
QtWidgets.QMessageBox.information(self,
|
|
|
|
translate('OpenLP.ThemeManager', 'Theme Exported'),
|
|
|
|
translate('OpenLP.ThemeManager',
|
|
|
|
'Your theme has been successfully exported.'))
|
2013-02-03 19:23:12 +00:00
|
|
|
self.application.set_normal_cursor()
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def _export_theme(self, theme_path, theme_name):
|
2014-06-23 13:51:56 +00:00
|
|
|
"""
|
|
|
|
Create the zipfile with the theme contents.
|
2017-09-26 16:39:13 +00:00
|
|
|
|
2019-05-22 06:47:00 +00:00
|
|
|
:param Path theme_path: Location where the zip file will be placed
|
2017-09-26 16:39:13 +00:00
|
|
|
:param str theme_name: The name of the theme to be exported
|
|
|
|
:return: The success of creating the zip file
|
|
|
|
:rtype: bool
|
2014-06-23 13:51:56 +00:00
|
|
|
"""
|
2014-06-30 07:30:19 +00:00
|
|
|
try:
|
2019-03-10 21:01:39 +00:00
|
|
|
with zipfile.ZipFile(theme_path, 'w') as theme_zip:
|
2017-09-26 16:39:13 +00:00
|
|
|
source_path = self.theme_path / theme_name
|
|
|
|
for file_path in source_path.iterdir():
|
2019-03-10 21:01:39 +00:00
|
|
|
theme_zip.write(file_path, Path(theme_name, file_path.name))
|
2015-02-06 22:17:24 +00:00
|
|
|
return True
|
|
|
|
except OSError as ose:
|
|
|
|
self.log_exception('Export Theme Failed')
|
|
|
|
critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
|
2017-09-26 16:39:13 +00:00
|
|
|
translate('OpenLP.ThemeManager',
|
2018-03-16 06:05:18 +00:00
|
|
|
'The {theme_name} export failed because this error occurred: {err}')
|
|
|
|
.format(theme_name=theme_name, err=ose.strerror))
|
2017-09-26 16:39:13 +00:00
|
|
|
if theme_path.exists():
|
2019-05-22 06:47:00 +00:00
|
|
|
shutil.rmtree(theme_path, ignore_errors=True)
|
2015-02-06 22:17:24 +00:00
|
|
|
return False
|
2014-06-23 13:51:56 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def on_import_theme(self, checked=None):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2013-03-16 11:05:52 +00:00
|
|
|
Opens a file dialog to select the theme file(s) to import before attempting to extract OpenLP themes from
|
2015-02-13 21:47:06 +00:00
|
|
|
those files. This process will only load version 2 themes.
|
2017-09-26 16:39:13 +00:00
|
|
|
|
|
|
|
:param bool checked: Sent by the QAction.triggered signal. It's not used in this method.
|
|
|
|
:rtype: None
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
file_paths, filter_used = FileDialog.getOpenFileNames(
|
2017-08-07 20:50:01 +00:00
|
|
|
self,
|
|
|
|
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
|
2017-08-26 15:06:11 +00:00
|
|
|
Settings().value(self.settings_section + '/last directory import'),
|
2017-08-07 20:50:01 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
|
|
|
|
self.log_info('New Themes {file_paths}'.format(file_paths=file_paths))
|
|
|
|
if not file_paths:
|
2011-03-19 15:38:26 +00:00
|
|
|
return
|
2013-02-03 19:23:12 +00:00
|
|
|
self.application.set_busy_cursor()
|
2017-08-07 20:50:01 +00:00
|
|
|
for file_path in file_paths:
|
2017-09-26 16:39:13 +00:00
|
|
|
self.unzip_theme(file_path, self.theme_path)
|
|
|
|
Settings().setValue(self.settings_section + '/last directory import', file_path.parent)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.load_themes()
|
2013-02-03 19:23:12 +00:00
|
|
|
self.application.set_normal_cursor()
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-19 19:50:14 +00:00
|
|
|
def load_first_time_themes(self):
|
|
|
|
"""
|
|
|
|
Imports any themes on start up and makes sure there is at least one theme
|
|
|
|
"""
|
|
|
|
self.application.set_busy_cursor()
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_paths = AppLocation.get_files(self.settings_section, '.otz')
|
|
|
|
for theme_path in theme_paths:
|
|
|
|
theme_path = self.theme_path / theme_path
|
|
|
|
self.unzip_theme(theme_path, self.theme_path)
|
|
|
|
delete_file(theme_path)
|
|
|
|
theme_paths = AppLocation.get_files(self.settings_section, '.png')
|
2013-02-19 19:50:14 +00:00
|
|
|
# No themes have been found so create one
|
2017-09-26 16:39:13 +00:00
|
|
|
if not theme_paths:
|
2017-05-13 07:47:22 +00:00
|
|
|
theme = Theme()
|
2013-02-19 19:50:14 +00:00
|
|
|
theme.theme_name = UiStrings().Default
|
2019-06-06 20:10:39 +00:00
|
|
|
self.save_theme(theme)
|
2013-08-31 18:17:38 +00:00
|
|
|
Settings().setValue(self.settings_section + '/global theme', theme.theme_name)
|
2013-02-19 19:50:14 +00:00
|
|
|
self.application.set_normal_cursor()
|
|
|
|
|
|
|
|
def load_themes(self):
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2013-10-23 19:25:46 +00:00
|
|
|
Loads the theme lists and triggers updates across the whole system using direct calls or core functions and
|
|
|
|
events for the plugins.
|
2009-09-13 15:14:45 +00:00
|
|
|
The plugins will call back in to get the real list if they want it.
|
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list = []
|
|
|
|
self.theme_list_widget.clear()
|
2013-08-31 18:17:38 +00:00
|
|
|
files = AppLocation.get_files(self.settings_section, '.png')
|
2013-01-10 23:07:48 +00:00
|
|
|
# Sort the themes by its name considering language specific
|
2013-08-31 18:17:38 +00:00
|
|
|
files.sort(key=lambda file_name: get_locale_key(str(file_name)))
|
2011-03-20 07:37:44 +00:00
|
|
|
# now process the file list of png files
|
2017-09-26 16:39:13 +00:00
|
|
|
for file in files:
|
2011-03-20 07:37:44 +00:00
|
|
|
# check to see file is in theme root directory
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_path = self.theme_path / file
|
|
|
|
if theme_path.exists():
|
|
|
|
text_name = theme_path.stem
|
2012-03-10 16:03:58 +00:00
|
|
|
if text_name == self.global_theme:
|
2016-05-20 16:22:06 +00:00
|
|
|
name = translate('OpenLP.ThemeManager', '{name} (default)').format(name=text_name)
|
2011-03-20 07:37:44 +00:00
|
|
|
else:
|
2012-03-10 16:03:58 +00:00
|
|
|
name = text_name
|
2017-11-18 11:23:15 +00:00
|
|
|
thumb_path = self.thumb_path / '{name}.png'.format(name=text_name)
|
2015-11-07 00:49:40 +00:00
|
|
|
item_name = QtWidgets.QListWidgetItem(name)
|
2017-11-18 11:23:15 +00:00
|
|
|
if validate_thumb(theme_path, thumb_path):
|
|
|
|
icon = build_icon(thumb_path)
|
2011-03-20 07:37:44 +00:00
|
|
|
else:
|
2017-11-18 11:23:15 +00:00
|
|
|
icon = create_thumb(theme_path, thumb_path)
|
2011-03-20 07:37:44 +00:00
|
|
|
item_name.setIcon(icon)
|
2012-05-17 15:13:09 +00:00
|
|
|
item_name.setData(QtCore.Qt.UserRole, text_name)
|
2013-02-01 21:48:06 +00:00
|
|
|
self.theme_list_widget.addItem(item_name)
|
|
|
|
self.theme_list.append(text_name)
|
|
|
|
self._push_themes()
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def _push_themes(self):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
|
|
|
Notify listeners that the theme list has been updated
|
|
|
|
"""
|
2013-08-31 18:17:38 +00:00
|
|
|
Registry().execute('theme_update_list', self.get_themes())
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def get_themes(self):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
|
|
|
Return the list of loaded themes
|
|
|
|
"""
|
2013-02-01 21:48:06 +00:00
|
|
|
return self.theme_list
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def get_theme_data(self, theme_name):
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
Returns a theme object from a JSON file
|
2010-06-10 01:57:59 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
:param str theme_name: Name of the theme to load from file
|
|
|
|
:return: The theme object.
|
|
|
|
:rtype: Theme
|
2010-06-10 01:57:59 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_name = str(theme_name)
|
|
|
|
theme_file_path = self.theme_path / theme_name / '{file_name}.json'.format(file_name=theme_name)
|
2017-08-12 17:45:56 +00:00
|
|
|
theme_data = get_text_file_string(theme_file_path)
|
2017-05-13 08:22:48 +00:00
|
|
|
if not theme_data:
|
2013-12-23 07:03:56 +00:00
|
|
|
self.log_debug('No theme data - using default theme')
|
2017-05-13 07:47:22 +00:00
|
|
|
return Theme()
|
2017-09-26 16:39:13 +00:00
|
|
|
return self._create_theme_from_json(theme_data, self.theme_path)
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def over_write_message_box(self, theme_name):
|
|
|
|
"""
|
2013-02-01 21:34:23 +00:00
|
|
|
Display a warning box to the user that a theme already exists
|
2014-01-11 17:52:01 +00:00
|
|
|
|
2014-01-01 09:33:07 +00:00
|
|
|
:param theme_name: Name of the theme.
|
2015-09-08 19:13:59 +00:00
|
|
|
:return: Confirm if the theme is to be overwritten.
|
2013-02-01 21:48:06 +00:00
|
|
|
"""
|
2015-11-07 00:49:40 +00:00
|
|
|
ret = QtWidgets.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
|
|
|
|
translate('OpenLP.ThemeManager',
|
2016-05-20 16:22:06 +00:00
|
|
|
'Theme {name} already exists. '
|
|
|
|
'Do you want to replace it?').format(name=theme_name),
|
2017-05-30 18:42:35 +00:00
|
|
|
defaultButton=QtWidgets.QMessageBox.No)
|
2015-11-07 00:49:40 +00:00
|
|
|
return ret == QtWidgets.QMessageBox.Yes
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def unzip_theme(self, file_path, directory_path):
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2014-01-01 09:33:07 +00:00
|
|
|
Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
|
|
|
|
and upgrade if necessary.
|
2019-05-22 06:47:00 +00:00
|
|
|
:param Path file_path:
|
|
|
|
:param Path directory_path:
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
self.log_debug('Unzipping theme {name}'.format(name=file_path))
|
2012-03-10 08:22:52 +00:00
|
|
|
file_xml = None
|
2012-06-15 16:19:46 +00:00
|
|
|
abort_import = True
|
2017-05-30 13:55:39 +00:00
|
|
|
json_theme = False
|
|
|
|
theme_name = ""
|
2009-09-14 18:53:56 +00:00
|
|
|
try:
|
2019-03-10 21:01:39 +00:00
|
|
|
with zipfile.ZipFile(file_path) as theme_zip:
|
2017-09-26 16:39:13 +00:00
|
|
|
json_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.json']
|
|
|
|
if len(json_file) != 1:
|
2019-03-03 09:49:01 +00:00
|
|
|
# TODO: remove XML handling after once the upgrade path from 2.4 is no longer required
|
2017-09-26 16:39:13 +00:00
|
|
|
xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml']
|
|
|
|
if len(xml_file) != 1:
|
|
|
|
self.log_error('Theme contains "{val:d}" theme files'.format(val=len(xml_file)))
|
|
|
|
raise ValidationError
|
|
|
|
xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
|
|
|
|
theme_version = xml_tree.get('version', default=None)
|
|
|
|
if not theme_version or float(theme_version) < 2.0:
|
|
|
|
self.log_error('Theme version is less than 2.0')
|
|
|
|
raise ValidationError
|
|
|
|
theme_name = xml_tree.find('name').text.strip()
|
|
|
|
else:
|
|
|
|
new_theme = Theme()
|
|
|
|
new_theme.load_theme(theme_zip.read(json_file[0]).decode("utf-8"))
|
|
|
|
theme_name = new_theme.theme_name
|
|
|
|
json_theme = True
|
|
|
|
theme_folder = directory_path / theme_name
|
|
|
|
if theme_folder.exists() and not self.over_write_message_box(theme_name):
|
|
|
|
abort_import = True
|
|
|
|
return
|
2012-03-09 21:43:27 +00:00
|
|
|
else:
|
2017-09-26 16:39:13 +00:00
|
|
|
abort_import = False
|
|
|
|
for zipped_file in theme_zip.namelist():
|
|
|
|
zipped_file_rel_path = Path(zipped_file)
|
|
|
|
split_name = zipped_file_rel_path.parts
|
|
|
|
if split_name[-1] == '' or len(split_name) == 1:
|
|
|
|
# is directory or preview file
|
|
|
|
continue
|
|
|
|
full_name = directory_path / zipped_file_rel_path
|
2017-10-07 07:05:07 +00:00
|
|
|
create_paths(full_name.parent)
|
2017-09-26 16:39:13 +00:00
|
|
|
if zipped_file_rel_path.suffix.lower() == '.xml' or zipped_file_rel_path.suffix.lower() == '.json':
|
|
|
|
file_xml = str(theme_zip.read(zipped_file), 'utf-8')
|
|
|
|
with full_name.open('w', encoding='utf-8') as out_file:
|
|
|
|
out_file.write(file_xml)
|
|
|
|
else:
|
|
|
|
with full_name.open('wb') as out_file:
|
|
|
|
out_file.write(theme_zip.read(zipped_file))
|
2019-03-03 09:49:01 +00:00
|
|
|
except (OSError, ValidationError, zipfile.BadZipFile):
|
2017-09-26 16:39:13 +00:00
|
|
|
self.log_exception('Importing theme from zip failed {name}'.format(name=file_path))
|
2019-03-03 09:49:01 +00:00
|
|
|
critical_error_message_box(
|
|
|
|
translate('OpenLP.ThemeManager', 'Import Error'),
|
|
|
|
translate('OpenLP.ThemeManager', 'There was a problem imoorting {file_name}.\n\nIt is corrupt,'
|
|
|
|
'inaccessible or not a valid theme.').format(file_name=file_path))
|
2011-02-17 12:53:07 +00:00
|
|
|
finally:
|
2012-03-10 08:22:52 +00:00
|
|
|
if not abort_import:
|
2012-03-09 21:43:27 +00:00
|
|
|
# As all files are closed, we can create the Theme.
|
2012-03-10 08:22:52 +00:00
|
|
|
if file_xml:
|
2017-05-21 15:30:02 +00:00
|
|
|
if json_theme:
|
2017-09-26 16:39:13 +00:00
|
|
|
theme = self._create_theme_from_json(file_xml, self.theme_path)
|
2017-05-21 15:30:02 +00:00
|
|
|
else:
|
2017-09-26 16:39:13 +00:00
|
|
|
theme = self._create_theme_from_xml(file_xml, self.theme_path)
|
2013-12-30 19:50:34 +00:00
|
|
|
self.generate_and_save_image(theme_name, theme)
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def check_if_theme_exists(self, theme_name):
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2010-12-27 10:18:09 +00:00
|
|
|
Check if theme already exists and displays error message
|
2010-06-10 01:57:59 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
:param str theme_name: Name of the Theme to test
|
2015-09-08 19:13:59 +00:00
|
|
|
:return: True or False if theme exists
|
2017-09-26 16:39:13 +00:00
|
|
|
:rtype: bool
|
2010-12-27 10:18:09 +00:00
|
|
|
"""
|
2017-09-26 16:39:13 +00:00
|
|
|
if (self.theme_path / theme_name).exists():
|
2011-02-02 23:12:31 +00:00
|
|
|
critical_error_message_box(
|
2011-01-15 19:24:50 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'Validation Error'),
|
2012-12-29 15:25:29 +00:00
|
|
|
translate('OpenLP.ThemeManager', 'A theme with this name already exists.'))
|
2010-12-27 10:18:09 +00:00
|
|
|
return False
|
|
|
|
return True
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2019-06-07 21:05:02 +00:00
|
|
|
def save_theme(self, theme, image_source_path=None, image_destination_path=None, image=None):
|
2011-02-05 09:30:59 +00:00
|
|
|
"""
|
2013-12-24 06:15:41 +00:00
|
|
|
Writes the theme to the disk and handles the background image if necessary
|
2014-01-01 09:33:07 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
:param Theme theme: The theme data object.
|
2019-05-22 06:47:00 +00:00
|
|
|
:param Path image_source_path: Where the theme image is currently located.
|
|
|
|
:param Path image_destination_path: Where the Theme Image is to be saved to
|
2019-05-28 20:37:50 +00:00
|
|
|
:param image: The example image of the theme. Optionally.
|
2017-09-26 16:39:13 +00:00
|
|
|
:rtype: None
|
2011-02-05 09:30:59 +00:00
|
|
|
"""
|
2010-11-05 19:20:41 +00:00
|
|
|
name = theme.theme_name
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_pretty = theme.export_theme(self.theme_path)
|
|
|
|
theme_dir = self.theme_path / name
|
2017-10-07 07:05:07 +00:00
|
|
|
create_paths(theme_dir)
|
2017-09-26 16:39:13 +00:00
|
|
|
theme_path = theme_dir / '{file_name}.json'.format(file_name=name)
|
2010-12-27 10:18:09 +00:00
|
|
|
try:
|
2019-02-13 20:54:35 +00:00
|
|
|
theme_path.write_text(theme_pretty)
|
2017-11-03 20:55:41 +00:00
|
|
|
except OSError:
|
2013-12-23 07:03:56 +00:00
|
|
|
self.log_exception('Saving theme to file failed')
|
2017-09-26 16:39:13 +00:00
|
|
|
if image_source_path and image_destination_path:
|
|
|
|
if self.old_background_image_path and image_destination_path != self.old_background_image_path:
|
|
|
|
delete_file(self.old_background_image_path)
|
|
|
|
if image_source_path != image_destination_path:
|
|
|
|
try:
|
2019-05-22 06:47:00 +00:00
|
|
|
shutil.copyfile(image_source_path, image_destination_path)
|
2017-11-03 20:55:41 +00:00
|
|
|
except OSError:
|
2017-09-26 16:39:13 +00:00
|
|
|
self.log_exception('Failed to save theme image')
|
2019-05-28 20:37:50 +00:00
|
|
|
if image:
|
|
|
|
sample_path_name = self.theme_path / '{file_name}.png'.format(file_name=name)
|
|
|
|
if sample_path_name.exists():
|
|
|
|
sample_path_name.unlink()
|
|
|
|
image.save(str(sample_path_name), 'png')
|
|
|
|
thumb_path = self.thumb_path / '{name}.png'.format(name=name)
|
|
|
|
create_thumb(sample_path_name, thumb_path, False)
|
|
|
|
else:
|
|
|
|
self.generate_and_save_image(name, theme)
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def generate_and_save_image(self, theme_name, theme):
|
2013-02-01 21:48:06 +00:00
|
|
|
"""
|
2013-02-01 21:34:23 +00:00
|
|
|
Generate and save a preview image
|
2014-01-01 09:33:07 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
:param str theme_name: The name of the theme.
|
2014-01-01 09:33:07 +00:00
|
|
|
:param theme: The theme data object.
|
2013-02-01 21:48:06 +00:00
|
|
|
"""
|
|
|
|
frame = self.generate_image(theme)
|
2017-09-26 16:39:13 +00:00
|
|
|
sample_path_name = self.theme_path / '{file_name}.png'.format(file_name=theme_name)
|
|
|
|
if sample_path_name.exists():
|
|
|
|
sample_path_name.unlink()
|
|
|
|
frame.save(str(sample_path_name), 'png')
|
|
|
|
thumb_path = self.thumb_path / '{name}.png'.format(name=theme_name)
|
2017-11-18 11:23:15 +00:00
|
|
|
create_thumb(sample_path_name, thumb_path, False)
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2013-02-01 21:48:06 +00:00
|
|
|
def update_preview_images(self):
|
2011-05-20 11:45:39 +00:00
|
|
|
"""
|
|
|
|
Called to update the themes' preview images.
|
|
|
|
"""
|
2013-03-16 11:05:52 +00:00
|
|
|
self.main_window.display_progress_bar(len(self.theme_list))
|
2013-02-01 21:48:06 +00:00
|
|
|
for theme in self.theme_list:
|
2013-03-07 08:05:43 +00:00
|
|
|
self.main_window.increment_progress_bar()
|
2013-12-30 19:50:34 +00:00
|
|
|
self.generate_and_save_image(theme, self.get_theme_data(theme))
|
2013-03-16 11:05:52 +00:00
|
|
|
self.main_window.finished_progress_bar()
|
2013-02-01 21:48:06 +00:00
|
|
|
self.load_themes()
|
2011-05-20 11:45:39 +00:00
|
|
|
|
2013-10-23 19:25:46 +00:00
|
|
|
def generate_image(self, theme_data, force_page=False):
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2011-03-28 18:56:39 +00:00
|
|
|
Call the renderer to build a Sample Image
|
2010-11-24 21:50:51 +00:00
|
|
|
|
2014-01-01 09:33:07 +00:00
|
|
|
:param theme_data: The theme to generated a preview for.
|
2017-11-20 21:57:34 +00:00
|
|
|
:param force_page: Flag to tell message lines per page need to be generated.
|
2017-11-18 11:23:15 +00:00
|
|
|
:rtype: QtGui.QPixmap
|
2009-09-13 15:14:45 +00:00
|
|
|
"""
|
2013-10-23 19:25:46 +00:00
|
|
|
return self.renderer.generate_preview(theme_data, force_page)
|
2009-09-13 15:14:45 +00:00
|
|
|
|
2017-05-13 07:47:22 +00:00
|
|
|
@staticmethod
|
|
|
|
def _create_theme_from_xml(theme_xml, image_path):
|
2010-06-10 19:45:02 +00:00
|
|
|
"""
|
|
|
|
Return a theme object using information parsed from XML
|
|
|
|
|
2014-01-01 09:33:07 +00:00
|
|
|
:param theme_xml: The Theme data object.
|
2019-05-22 06:47:00 +00:00
|
|
|
:param Path image_path: Where the theme image is stored
|
2015-09-08 19:13:59 +00:00
|
|
|
:return: Theme data.
|
2017-09-26 16:39:13 +00:00
|
|
|
:rtype: Theme
|
2010-06-10 19:45:02 +00:00
|
|
|
"""
|
2017-05-13 07:47:22 +00:00
|
|
|
theme = Theme()
|
2012-03-10 16:03:58 +00:00
|
|
|
theme.parse(theme_xml)
|
2014-01-01 09:33:07 +00:00
|
|
|
theme.extend_image_filename(image_path)
|
2009-11-06 02:12:56 +00:00
|
|
|
return theme
|
2010-12-22 18:49:01 +00:00
|
|
|
|
2017-09-26 16:39:13 +00:00
|
|
|
def _create_theme_from_json(self, theme_json, image_path):
|
2017-05-13 07:47:22 +00:00
|
|
|
"""
|
|
|
|
Return a theme object using information parsed from JSON
|
|
|
|
|
|
|
|
:param theme_json: The Theme data object.
|
2019-05-22 06:47:00 +00:00
|
|
|
:param Path image_path: Where the theme image is stored
|
2017-05-13 07:47:22 +00:00
|
|
|
:return: Theme data.
|
2017-09-26 16:39:13 +00:00
|
|
|
:rtype: Theme
|
2017-05-13 07:47:22 +00:00
|
|
|
"""
|
|
|
|
theme = Theme()
|
2017-09-26 16:39:13 +00:00
|
|
|
theme.load_theme(theme_json, self.theme_path)
|
2017-05-13 07:47:22 +00:00
|
|
|
theme.extend_image_filename(image_path)
|
|
|
|
return theme
|
|
|
|
|
2013-10-23 19:25:46 +00:00
|
|
|
def _validate_theme_action(self, select_text, confirm_title, confirm_text, test_plugin=True, confirm=True):
|
2010-12-22 18:49:01 +00:00
|
|
|
"""
|
2013-12-24 06:15:41 +00:00
|
|
|
Check to see if theme has been selected and the destructive action is allowed.
|
2014-01-01 09:33:07 +00:00
|
|
|
|
|
|
|
:param select_text: Text for message box if no item selected.
|
|
|
|
:param confirm_title: Confirm message title to be displayed.
|
|
|
|
:param confirm_text: Confirm message text to be displayed.
|
|
|
|
:param test_plugin: Do we check the plugins for theme usage.
|
|
|
|
:param confirm: Do we display a confirm box before run checks.
|
2015-09-08 19:13:59 +00:00
|
|
|
:return: True or False depending on the validity.
|
2010-12-22 18:49:01 +00:00
|
|
|
"""
|
2013-08-31 18:17:38 +00:00
|
|
|
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
2013-02-01 21:48:06 +00:00
|
|
|
if check_item_selected(self.theme_list_widget, select_text):
|
|
|
|
item = self.theme_list_widget.currentItem()
|
2012-05-17 18:57:01 +00:00
|
|
|
theme = item.text()
|
2010-12-22 18:49:01 +00:00
|
|
|
# confirm deletion
|
2011-02-05 17:31:13 +00:00
|
|
|
if confirm:
|
2015-11-07 00:49:40 +00:00
|
|
|
answer = QtWidgets.QMessageBox.question(
|
2017-05-30 18:42:35 +00:00
|
|
|
self, confirm_title, confirm_text.format(theme_name=theme),
|
|
|
|
defaultButton=QtWidgets.QMessageBox.No)
|
2015-11-07 00:49:40 +00:00
|
|
|
if answer == QtWidgets.QMessageBox.No:
|
2011-02-05 17:31:13 +00:00
|
|
|
return False
|
2010-12-22 18:49:01 +00:00
|
|
|
# should be the same unless default
|
2012-05-19 15:10:05 +00:00
|
|
|
if theme != item.data(QtCore.Qt.UserRole):
|
2011-02-02 23:12:31 +00:00
|
|
|
critical_error_message_box(
|
2012-12-29 15:25:29 +00:00
|
|
|
message=translate('OpenLP.ThemeManager', 'You are unable to delete the default theme.'))
|
2010-12-31 02:17:41 +00:00
|
|
|
return False
|
2010-12-27 10:18:09 +00:00
|
|
|
# check for use in the system else where.
|
2013-10-23 19:25:46 +00:00
|
|
|
if test_plugin:
|
2015-10-16 16:30:13 +00:00
|
|
|
plugin_usage = ""
|
2019-07-31 21:01:22 +00:00
|
|
|
for plugin in State().list_plugins():
|
2015-10-16 16:30:13 +00:00
|
|
|
used_count = plugin.uses_theme(theme)
|
|
|
|
if used_count:
|
2016-05-20 16:22:06 +00:00
|
|
|
plugin_usage = "{plug}{text}".format(plug=plugin_usage,
|
|
|
|
text=(translate('OpenLP.ThemeManager',
|
|
|
|
'{count} time(s) by {plugin}'
|
|
|
|
).format(name=used_count,
|
|
|
|
plugin=plugin.name)))
|
2016-06-04 00:15:19 +00:00
|
|
|
plugin_usage = "{text}\n".format(text=plugin_usage)
|
2015-10-16 16:30:13 +00:00
|
|
|
if plugin_usage:
|
|
|
|
critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'),
|
2016-05-20 16:22:06 +00:00
|
|
|
translate('OpenLP.ThemeManager',
|
|
|
|
'Theme is currently used \n\n{text}'
|
|
|
|
).format(text=plugin_usage))
|
2015-10-16 16:30:13 +00:00
|
|
|
|
|
|
|
return False
|
2011-05-03 17:05:17 +00:00
|
|
|
return True
|
2014-03-20 19:10:31 +00:00
|
|
|
return False
|