forked from openlp/openlp
HEAD
This commit is contained in:
commit
d8a32d3962
@ -46,34 +46,14 @@ from openlp.core.ui.exceptionform import ExceptionForm
|
|||||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||||
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
|
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
|
||||||
from openlp.core.ui.mainwindow import MainWindow
|
from openlp.core.ui.mainwindow import MainWindow
|
||||||
|
from openlp.core.ui.style import get_application_stylesheet
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['OpenLP', 'main']
|
__all__ = ['OpenLP', 'main']
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
|
|
||||||
WIN_REPAIR_STYLESHEET = """
|
|
||||||
QMainWindow::separator
|
|
||||||
{
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDockWidget::title
|
|
||||||
{
|
|
||||||
border: 1px solid palette(dark);
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-top: 2px;
|
|
||||||
margin: 1px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QToolBar
|
|
||||||
{
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||||
"""
|
"""
|
||||||
@ -118,14 +98,7 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
|||||||
QtCore.QCoreApplication.exit()
|
QtCore.QCoreApplication.exit()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
# Correct stylesheet bugs
|
# Correct stylesheet bugs
|
||||||
application_stylesheet = ''
|
application_stylesheet = get_application_stylesheet()
|
||||||
if not Settings().value('advanced/alternate rows'):
|
|
||||||
base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
|
|
||||||
alternate_rows_repair_stylesheet = \
|
|
||||||
'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
|
|
||||||
application_stylesheet += alternate_rows_repair_stylesheet
|
|
||||||
if is_win():
|
|
||||||
application_stylesheet += WIN_REPAIR_STYLESHEET
|
|
||||||
if application_stylesheet:
|
if application_stylesheet:
|
||||||
self.setStyleSheet(application_stylesheet)
|
self.setStyleSheet(application_stylesheet)
|
||||||
can_show_splash = Settings().value('core/show splash')
|
can_show_splash = Settings().value('core/show splash')
|
||||||
|
@ -63,7 +63,7 @@ def download_and_check(callback=None):
|
|||||||
sha256, version = download_sha256()
|
sha256, version = download_sha256()
|
||||||
file_size = get_url_file_size('https://get.openlp.org/webclient/site.zip')
|
file_size = get_url_file_size('https://get.openlp.org/webclient/site.zip')
|
||||||
callback.setRange(0, file_size)
|
callback.setRange(0, file_size)
|
||||||
if url_get_file(callback, '{host}{name}'.format(host='https://get.openlp.org/webclient/', name='site.zip'),
|
if url_get_file(callback, 'https://get.openlp.org/webclient/site.zip',
|
||||||
AppLocation.get_section_data_path('remotes') / 'site.zip',
|
AppLocation.get_section_data_path('remotes') / 'site.zip',
|
||||||
sha256=sha256):
|
sha256=sha256):
|
||||||
deploy_zipfile(str(AppLocation.get_section_data_path('remotes')), 'site.zip')
|
deploy_zipfile(str(AppLocation.get_section_data_path('remotes')), 'site.zip')
|
@ -21,18 +21,13 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from openlp.core.api.http.endpoint import Endpoint
|
from openlp.core.api.http.endpoint import Endpoint
|
||||||
from openlp.core.api.endpoint.core import TRANSLATED_STRINGS
|
from openlp.core.api.endpoint.core import TRANSLATED_STRINGS
|
||||||
from openlp.core.common import AppLocation
|
|
||||||
|
|
||||||
|
|
||||||
static_dir = os.path.join(str(AppLocation.get_section_data_path('remotes')))
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
remote_endpoint = Endpoint('remote', template_dir=static_dir, static_dir=static_dir)
|
remote_endpoint = Endpoint('remote', template_dir='remotes', static_dir='remotes')
|
||||||
|
|
||||||
|
|
||||||
@remote_endpoint.route('{view}')
|
@remote_endpoint.route('{view}')
|
@ -23,7 +23,7 @@ import logging
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from openlp.core.api.http.endpoint import Endpoint
|
from openlp.core.api.http.endpoint import Endpoint
|
||||||
from openlp.core.api.http import register_endpoint, requires_auth
|
from openlp.core.api.http import requires_auth
|
||||||
from openlp.core.common import Registry
|
from openlp.core.common import Registry
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,17 +26,24 @@ with OpenLP. It uses JSON to communicate with the remotes.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore, QtWidgets
|
||||||
from waitress import serve
|
from waitress import serve
|
||||||
|
|
||||||
from openlp.core.api.http import register_endpoint
|
from openlp.core.api.http import register_endpoint
|
||||||
from openlp.core.api.http import application
|
from openlp.core.api.http import application
|
||||||
from openlp.core.common import RegistryMixin, RegistryProperties, OpenLPMixin, Settings, Registry
|
from openlp.core.common import AppLocation, RegistryMixin, RegistryProperties, OpenLPMixin, \
|
||||||
|
Settings, Registry, UiStrings, check_directory_exists
|
||||||
|
from openlp.core.lib import translate
|
||||||
|
|
||||||
|
from openlp.core.api.deploy import download_and_check, download_sha256
|
||||||
from openlp.core.api.poll import Poller
|
from openlp.core.api.poll import Poller
|
||||||
from openlp.core.api.endpoint.controller import controller_endpoint, api_controller_endpoint
|
from openlp.core.api.endpoint.controller import controller_endpoint, api_controller_endpoint
|
||||||
from openlp.core.api.endpoint.core import chords_endpoint, stage_endpoint, blank_endpoint, main_endpoint
|
from openlp.core.api.endpoint.core import chords_endpoint, stage_endpoint, blank_endpoint, main_endpoint
|
||||||
from openlp.core.api.endpoint.service import service_endpoint, api_service_endpoint
|
from openlp.core.api.endpoint.service import service_endpoint, api_service_endpoint
|
||||||
|
from openlp.core.api.endpoint.remote import remote_endpoint
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -59,6 +66,7 @@ class HttpWorker(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
address = Settings().value('api/ip address')
|
address = Settings().value('api/ip address')
|
||||||
port = Settings().value('api/port')
|
port = Settings().value('api/port')
|
||||||
|
Registry().execute('get_website_version')
|
||||||
serve(application, host=address, port=port)
|
serve(application, host=address, port=port)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
@ -79,11 +87,15 @@ class HttpServer(RegistryMixin, RegistryProperties, OpenLPMixin):
|
|||||||
self.worker.moveToThread(self.thread)
|
self.worker.moveToThread(self.thread)
|
||||||
self.thread.started.connect(self.worker.run)
|
self.thread.started.connect(self.worker.run)
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
Registry().register_function('download_website', self.first_time)
|
||||||
|
Registry().register_function('get_website_version', self.website_version)
|
||||||
|
Registry().set_flag('website_version', '0.0')
|
||||||
|
|
||||||
def bootstrap_post_set_up(self):
|
def bootstrap_post_set_up(self):
|
||||||
"""
|
"""
|
||||||
Register the poll return service and start the servers.
|
Register the poll return service and start the servers.
|
||||||
"""
|
"""
|
||||||
|
self.initialise()
|
||||||
self.poller = Poller()
|
self.poller = Poller()
|
||||||
Registry().register('poller', self.poller)
|
Registry().register('poller', self.poller)
|
||||||
application.initialise()
|
application.initialise()
|
||||||
@ -95,3 +107,79 @@ class HttpServer(RegistryMixin, RegistryProperties, OpenLPMixin):
|
|||||||
register_endpoint(main_endpoint)
|
register_endpoint(main_endpoint)
|
||||||
register_endpoint(service_endpoint)
|
register_endpoint(service_endpoint)
|
||||||
register_endpoint(api_service_endpoint)
|
register_endpoint(api_service_endpoint)
|
||||||
|
register_endpoint(remote_endpoint)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def initialise():
|
||||||
|
"""
|
||||||
|
Create the internal file structure if it does not exist
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets')
|
||||||
|
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images')
|
||||||
|
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static')
|
||||||
|
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static' / 'index')
|
||||||
|
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates')
|
||||||
|
|
||||||
|
def first_time(self):
|
||||||
|
"""
|
||||||
|
Import web site code if active
|
||||||
|
"""
|
||||||
|
self.application.process_events()
|
||||||
|
progress = DownloadProgressDialog(self)
|
||||||
|
progress.forceShow()
|
||||||
|
self.application.process_events()
|
||||||
|
time.sleep(1)
|
||||||
|
download_and_check(progress)
|
||||||
|
self.application.process_events()
|
||||||
|
time.sleep(1)
|
||||||
|
progress.close()
|
||||||
|
self.application.process_events()
|
||||||
|
Settings().setValue('remotes/download version', self.version)
|
||||||
|
|
||||||
|
def website_version(self):
|
||||||
|
"""
|
||||||
|
Download and save the website version and sha256
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
sha256, self.version = download_sha256()
|
||||||
|
Registry().set_flag('website_sha256', sha256)
|
||||||
|
Registry().set_flag('website_version', self.version)
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadProgressDialog(QtWidgets.QProgressDialog):
|
||||||
|
"""
|
||||||
|
Local class to handle download display based and supporting httputils:get_web_page
|
||||||
|
"""
|
||||||
|
def __init__(self, parent):
|
||||||
|
super(DownloadProgressDialog, self).__init__(parent.main_window)
|
||||||
|
self.parent = parent
|
||||||
|
self.setWindowModality(QtCore.Qt.WindowModal)
|
||||||
|
self.setWindowTitle(translate('RemotePlugin', 'Importing Website'))
|
||||||
|
self.setLabelText(UiStrings().StartingImport)
|
||||||
|
self.setCancelButton(None)
|
||||||
|
self.setRange(0, 1)
|
||||||
|
self.setMinimumDuration(0)
|
||||||
|
self.was_cancelled = False
|
||||||
|
self.previous_size = 0
|
||||||
|
|
||||||
|
def _download_progress(self, count, block_size):
|
||||||
|
"""
|
||||||
|
Calculate and display the download progress.
|
||||||
|
"""
|
||||||
|
increment = (count * block_size) - self.previous_size
|
||||||
|
self._increment_progress_bar(None, increment)
|
||||||
|
self.previous_size = count * block_size
|
||||||
|
|
||||||
|
def _increment_progress_bar(self, status_text, increment=1):
|
||||||
|
"""
|
||||||
|
Update the wizard progress page.
|
||||||
|
|
||||||
|
:param status_text: Current status information to display.
|
||||||
|
:param increment: The value to increment the progress bar by.
|
||||||
|
"""
|
||||||
|
if status_text:
|
||||||
|
self.setText(status_text)
|
||||||
|
if increment > 0:
|
||||||
|
self.setValue(self.value() + increment)
|
||||||
|
self.parent.application.process_events()
|
||||||
|
@ -222,6 +222,8 @@ class ApiTab(SettingsTab):
|
|||||||
self.remote_url.setText('<a href="{url}">{url}</a>'.format(url=http_url))
|
self.remote_url.setText('<a href="{url}">{url}</a>'.format(url=http_url))
|
||||||
http_url_temp = http_url + 'stage'
|
http_url_temp = http_url + 'stage'
|
||||||
self.stage_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
self.stage_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
||||||
|
http_url_temp = http_url + 'chords'
|
||||||
|
self.chords_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
||||||
http_url_temp = http_url + 'main'
|
http_url_temp = http_url + 'main'
|
||||||
self.live_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
self.live_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ class Settings(QtCore.QSettings):
|
|||||||
'advanced/single click service preview': False,
|
'advanced/single click service preview': False,
|
||||||
'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
|
'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
|
||||||
'advanced/search as type': True,
|
'advanced/search as type': True,
|
||||||
|
'advanced/use_dark_style': False,
|
||||||
'api/twelve hour': True,
|
'api/twelve hour': True,
|
||||||
'api/port': 4316,
|
'api/port': 4316,
|
||||||
'api/websocket port': 4317,
|
'api/websocket port': 4317,
|
||||||
@ -177,6 +178,7 @@ class Settings(QtCore.QSettings):
|
|||||||
'images/background color': '#000000',
|
'images/background color': '#000000',
|
||||||
'media/players': 'system,webkit',
|
'media/players': 'system,webkit',
|
||||||
'media/override player': QtCore.Qt.Unchecked,
|
'media/override player': QtCore.Qt.Unchecked,
|
||||||
|
'remotes/download version': '0.0',
|
||||||
'players/background color': '#000000',
|
'players/background color': '#000000',
|
||||||
'servicemanager/last directory': None,
|
'servicemanager/last directory': None,
|
||||||
'servicemanager/last file': None,
|
'servicemanager/last file': None,
|
||||||
|
@ -32,6 +32,7 @@ from openlp.core.common.languagemanager import format_time
|
|||||||
from openlp.core.common.path import path_to_str
|
from openlp.core.common.path import path_to_str
|
||||||
from openlp.core.lib import SettingsTab, build_icon
|
from openlp.core.lib import SettingsTab, build_icon
|
||||||
from openlp.core.ui.lib import PathEdit, PathType
|
from openlp.core.ui.lib import PathEdit, PathType
|
||||||
|
from openlp.core.ui.style import HAS_DARK_STYLE
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -109,8 +110,80 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
|
self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
|
||||||
self.ui_layout.addRow(self.enable_auto_close_check_box)
|
self.ui_layout.addRow(self.enable_auto_close_check_box)
|
||||||
self.left_layout.addWidget(self.ui_group_box)
|
self.left_layout.addWidget(self.ui_group_box)
|
||||||
|
if HAS_DARK_STYLE:
|
||||||
|
self.use_dark_style_checkbox = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
|
self.use_dark_style_checkbox.setObjectName('use_dark_style_checkbox')
|
||||||
|
self.ui_layout.addRow(self.use_dark_style_checkbox)
|
||||||
|
# Data Directory
|
||||||
|
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
|
||||||
|
self.data_directory_group_box.setObjectName('data_directory_group_box')
|
||||||
|
self.data_directory_layout = QtWidgets.QFormLayout(self.data_directory_group_box)
|
||||||
|
self.data_directory_layout.setObjectName('data_directory_layout')
|
||||||
|
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
|
||||||
|
self.data_directory_new_label.setObjectName('data_directory_current_label')
|
||||||
|
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
|
||||||
|
default_path=AppLocation.get_directory(AppLocation.DataDir))
|
||||||
|
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
|
||||||
|
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
|
||||||
|
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
|
||||||
|
self.new_data_directory_has_files_label.setWordWrap(True)
|
||||||
|
self.data_directory_cancel_button = QtWidgets.QToolButton(self.data_directory_group_box)
|
||||||
|
self.data_directory_cancel_button.setObjectName('data_directory_cancel_button')
|
||||||
|
self.data_directory_cancel_button.setIcon(build_icon(':/general/general_delete.png'))
|
||||||
|
self.data_directory_copy_check_layout = QtWidgets.QHBoxLayout()
|
||||||
|
self.data_directory_copy_check_layout.setObjectName('data_directory_copy_check_layout')
|
||||||
|
self.data_directory_copy_check_box = QtWidgets.QCheckBox(self.data_directory_group_box)
|
||||||
|
self.data_directory_copy_check_box.setObjectName('data_directory_copy_check_box')
|
||||||
|
self.data_directory_copy_check_layout.addWidget(self.data_directory_copy_check_box)
|
||||||
|
self.data_directory_copy_check_layout.addStretch()
|
||||||
|
self.data_directory_copy_check_layout.addWidget(self.data_directory_cancel_button)
|
||||||
|
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
|
||||||
|
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
|
||||||
|
self.left_layout.addWidget(self.data_directory_group_box)
|
||||||
|
# Hide mouse
|
||||||
|
self.hide_mouse_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||||
|
self.hide_mouse_group_box.setObjectName('hide_mouse_group_box')
|
||||||
|
self.hide_mouse_layout = QtWidgets.QVBoxLayout(self.hide_mouse_group_box)
|
||||||
|
self.hide_mouse_layout.setObjectName('hide_mouse_layout')
|
||||||
|
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.hide_mouse_group_box)
|
||||||
|
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
|
||||||
|
self.hide_mouse_layout.addWidget(self.hide_mouse_check_box)
|
||||||
|
self.right_layout.addWidget(self.hide_mouse_group_box)
|
||||||
|
# Service Item Slide Limits
|
||||||
|
self.slide_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||||
|
self.slide_group_box.setObjectName('slide_group_box')
|
||||||
|
self.slide_layout = QtWidgets.QVBoxLayout(self.slide_group_box)
|
||||||
|
self.slide_layout.setObjectName('slide_layout')
|
||||||
|
self.slide_label = QtWidgets.QLabel(self.slide_group_box)
|
||||||
|
self.slide_label.setWordWrap(True)
|
||||||
|
self.slide_layout.addWidget(self.slide_label)
|
||||||
|
self.end_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
||||||
|
self.end_slide_radio_button.setObjectName('end_slide_radio_button')
|
||||||
|
self.slide_layout.addWidget(self.end_slide_radio_button)
|
||||||
|
self.wrap_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
||||||
|
self.wrap_slide_radio_button.setObjectName('wrap_slide_radio_button')
|
||||||
|
self.slide_layout.addWidget(self.wrap_slide_radio_button)
|
||||||
|
self.next_item_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
||||||
|
self.next_item_radio_button.setObjectName('next_item_radio_button')
|
||||||
|
self.slide_layout.addWidget(self.next_item_radio_button)
|
||||||
|
self.right_layout.addWidget(self.slide_group_box)
|
||||||
|
# Display Workarounds
|
||||||
|
self.display_workaround_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||||
|
self.display_workaround_group_box.setObjectName('display_workaround_group_box')
|
||||||
|
self.display_workaround_layout = QtWidgets.QVBoxLayout(self.display_workaround_group_box)
|
||||||
|
self.display_workaround_layout.setObjectName('display_workaround_layout')
|
||||||
|
self.ignore_aspect_ratio_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
|
||||||
|
self.ignore_aspect_ratio_check_box.setObjectName('ignore_aspect_ratio_check_box')
|
||||||
|
self.display_workaround_layout.addWidget(self.ignore_aspect_ratio_check_box)
|
||||||
|
self.x11_bypass_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
|
||||||
|
self.x11_bypass_check_box.setObjectName('x11_bypass_check_box')
|
||||||
|
self.display_workaround_layout.addWidget(self.x11_bypass_check_box)
|
||||||
|
self.alternate_rows_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
|
||||||
|
self.alternate_rows_check_box.setObjectName('alternate_rows_check_box')
|
||||||
|
self.display_workaround_layout.addWidget(self.alternate_rows_check_box)
|
||||||
|
self.right_layout.addWidget(self.display_workaround_group_box)
|
||||||
# Default service name
|
# Default service name
|
||||||
self.service_name_group_box = QtWidgets.QGroupBox(self.left_column)
|
self.service_name_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||||
self.service_name_group_box.setObjectName('service_name_group_box')
|
self.service_name_group_box.setObjectName('service_name_group_box')
|
||||||
self.service_name_layout = QtWidgets.QFormLayout(self.service_name_group_box)
|
self.service_name_layout = QtWidgets.QFormLayout(self.service_name_group_box)
|
||||||
self.service_name_check_box = QtWidgets.QCheckBox(self.service_name_group_box)
|
self.service_name_check_box = QtWidgets.QCheckBox(self.service_name_group_box)
|
||||||
@ -147,77 +220,11 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.service_name_example = QtWidgets.QLabel(self.service_name_group_box)
|
self.service_name_example = QtWidgets.QLabel(self.service_name_group_box)
|
||||||
self.service_name_example.setObjectName('service_name_example')
|
self.service_name_example.setObjectName('service_name_example')
|
||||||
self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
|
self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
|
||||||
self.left_layout.addWidget(self.service_name_group_box)
|
self.right_layout.addWidget(self.service_name_group_box)
|
||||||
# Data Directory
|
# After the last item on each side, add some spacing
|
||||||
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
|
|
||||||
self.data_directory_group_box.setObjectName('data_directory_group_box')
|
|
||||||
self.data_directory_layout = QtWidgets.QFormLayout(self.data_directory_group_box)
|
|
||||||
self.data_directory_layout.setObjectName('data_directory_layout')
|
|
||||||
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
|
|
||||||
self.data_directory_new_label.setObjectName('data_directory_current_label')
|
|
||||||
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
|
|
||||||
default_path=AppLocation.get_directory(AppLocation.DataDir))
|
|
||||||
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
|
|
||||||
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
|
|
||||||
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
|
|
||||||
self.new_data_directory_has_files_label.setWordWrap(True)
|
|
||||||
self.data_directory_cancel_button = QtWidgets.QToolButton(self.data_directory_group_box)
|
|
||||||
self.data_directory_cancel_button.setObjectName('data_directory_cancel_button')
|
|
||||||
self.data_directory_cancel_button.setIcon(build_icon(':/general/general_delete.png'))
|
|
||||||
self.data_directory_copy_check_layout = QtWidgets.QHBoxLayout()
|
|
||||||
self.data_directory_copy_check_layout.setObjectName('data_directory_copy_check_layout')
|
|
||||||
self.data_directory_copy_check_box = QtWidgets.QCheckBox(self.data_directory_group_box)
|
|
||||||
self.data_directory_copy_check_box.setObjectName('data_directory_copy_check_box')
|
|
||||||
self.data_directory_copy_check_layout.addWidget(self.data_directory_copy_check_box)
|
|
||||||
self.data_directory_copy_check_layout.addStretch()
|
|
||||||
self.data_directory_copy_check_layout.addWidget(self.data_directory_cancel_button)
|
|
||||||
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
|
|
||||||
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
|
|
||||||
self.left_layout.addWidget(self.data_directory_group_box)
|
|
||||||
self.left_layout.addStretch()
|
self.left_layout.addStretch()
|
||||||
# Hide mouse
|
|
||||||
self.hide_mouse_group_box = QtWidgets.QGroupBox(self.right_column)
|
|
||||||
self.hide_mouse_group_box.setObjectName('hide_mouse_group_box')
|
|
||||||
self.hide_mouse_layout = QtWidgets.QVBoxLayout(self.hide_mouse_group_box)
|
|
||||||
self.hide_mouse_layout.setObjectName('hide_mouse_layout')
|
|
||||||
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.hide_mouse_group_box)
|
|
||||||
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
|
|
||||||
self.hide_mouse_layout.addWidget(self.hide_mouse_check_box)
|
|
||||||
self.right_layout.addWidget(self.hide_mouse_group_box)
|
|
||||||
# Service Item Slide Limits
|
|
||||||
self.slide_group_box = QtWidgets.QGroupBox(self.right_column)
|
|
||||||
self.slide_group_box.setObjectName('slide_group_box')
|
|
||||||
self.slide_layout = QtWidgets.QVBoxLayout(self.slide_group_box)
|
|
||||||
self.slide_layout.setObjectName('slide_layout')
|
|
||||||
self.slide_label = QtWidgets.QLabel(self.slide_group_box)
|
|
||||||
self.slide_label.setWordWrap(True)
|
|
||||||
self.slide_layout.addWidget(self.slide_label)
|
|
||||||
self.end_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
|
||||||
self.end_slide_radio_button.setObjectName('end_slide_radio_button')
|
|
||||||
self.slide_layout.addWidget(self.end_slide_radio_button)
|
|
||||||
self.wrap_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
|
||||||
self.wrap_slide_radio_button.setObjectName('wrap_slide_radio_button')
|
|
||||||
self.slide_layout.addWidget(self.wrap_slide_radio_button)
|
|
||||||
self.next_item_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
|
||||||
self.next_item_radio_button.setObjectName('next_item_radio_button')
|
|
||||||
self.slide_layout.addWidget(self.next_item_radio_button)
|
|
||||||
self.right_layout.addWidget(self.slide_group_box)
|
|
||||||
# Display Workarounds
|
|
||||||
self.display_workaround_group_box = QtWidgets.QGroupBox(self.left_column)
|
|
||||||
self.display_workaround_group_box.setObjectName('display_workaround_group_box')
|
|
||||||
self.display_workaround_layout = QtWidgets.QVBoxLayout(self.display_workaround_group_box)
|
|
||||||
self.display_workaround_layout.setObjectName('display_workaround_layout')
|
|
||||||
self.ignore_aspect_ratio_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
|
|
||||||
self.ignore_aspect_ratio_check_box.setObjectName('ignore_aspect_ratio_check_box')
|
|
||||||
self.display_workaround_layout.addWidget(self.ignore_aspect_ratio_check_box)
|
|
||||||
self.x11_bypass_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
|
|
||||||
self.x11_bypass_check_box.setObjectName('x11_bypass_check_box')
|
|
||||||
self.display_workaround_layout.addWidget(self.x11_bypass_check_box)
|
|
||||||
self.alternate_rows_check_box = QtWidgets.QCheckBox(self.display_workaround_group_box)
|
|
||||||
self.alternate_rows_check_box.setObjectName('alternate_rows_check_box')
|
|
||||||
self.display_workaround_layout.addWidget(self.alternate_rows_check_box)
|
|
||||||
self.right_layout.addWidget(self.display_workaround_group_box)
|
|
||||||
self.right_layout.addStretch()
|
self.right_layout.addStretch()
|
||||||
|
# Set up all the connections and things
|
||||||
self.should_update_service_name_example = False
|
self.should_update_service_name_example = False
|
||||||
self.service_name_check_box.toggled.connect(self.service_name_check_box_toggled)
|
self.service_name_check_box.toggled.connect(self.service_name_check_box_toggled)
|
||||||
self.service_name_day.currentIndexChanged.connect(self.on_service_name_day_changed)
|
self.service_name_day.currentIndexChanged.connect(self.on_service_name_day_changed)
|
||||||
@ -282,6 +289,8 @@ class AdvancedTab(SettingsTab):
|
|||||||
'Auto-scroll the next slide to bottom'))
|
'Auto-scroll the next slide to bottom'))
|
||||||
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
|
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
|
||||||
'Enable application exit confirmation'))
|
'Enable application exit confirmation'))
|
||||||
|
if HAS_DARK_STYLE:
|
||||||
|
self.use_dark_style_checkbox.setText(translate('OpenLP.AdvancedTab', 'Use dark style (needs restart)'))
|
||||||
self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
|
self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
|
||||||
self.service_name_check_box.setText(translate('OpenLP.AdvancedTab', 'Enable default service name'))
|
self.service_name_check_box.setText(translate('OpenLP.AdvancedTab', 'Enable default service name'))
|
||||||
self.service_name_time_label.setText(translate('OpenLP.AdvancedTab', 'Date and Time:'))
|
self.service_name_time_label.setText(translate('OpenLP.AdvancedTab', 'Date and Time:'))
|
||||||
@ -349,6 +358,8 @@ class AdvancedTab(SettingsTab):
|
|||||||
if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
|
if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
|
||||||
self.autoscroll_combo_box.setCurrentIndex(i)
|
self.autoscroll_combo_box.setCurrentIndex(i)
|
||||||
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
|
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
|
||||||
|
if HAS_DARK_STYLE:
|
||||||
|
self.use_dark_style_checkbox.setChecked(settings.value('use_dark_style'))
|
||||||
self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
|
self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
|
||||||
self.service_name_day.setCurrentIndex(settings.value('default service day'))
|
self.service_name_day.setCurrentIndex(settings.value('default service day'))
|
||||||
self.service_name_time.setTime(QtCore.QTime(settings.value('default service hour'),
|
self.service_name_time.setTime(QtCore.QTime(settings.value('default service hour'),
|
||||||
@ -420,6 +431,8 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.settings_form.register_post_process('config_screen_changed')
|
self.settings_form.register_post_process('config_screen_changed')
|
||||||
self.settings_form.register_post_process('slidecontroller_update_slide_limits')
|
self.settings_form.register_post_process('slidecontroller_update_slide_limits')
|
||||||
settings.setValue('search as type', self.is_search_as_you_type_enabled)
|
settings.setValue('search as type', self.is_search_as_you_type_enabled)
|
||||||
|
if HAS_DARK_STYLE:
|
||||||
|
settings.setValue('use_dark_style', self.use_dark_style_checkbox.isChecked())
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
|
|
||||||
def on_search_as_type_check_box_changed(self, check_state):
|
def on_search_as_type_check_box_changed(self, check_state):
|
||||||
|
@ -51,31 +51,12 @@ from openlp.core.ui.projector.manager import ProjectorManager
|
|||||||
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
|
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
|
||||||
from openlp.core.ui.lib.filedialog import FileDialog
|
from openlp.core.ui.lib.filedialog import FileDialog
|
||||||
from openlp.core.ui.lib.mediadockmanager import MediaDockManager
|
from openlp.core.ui.lib.mediadockmanager import MediaDockManager
|
||||||
|
from openlp.core.ui.style import PROGRESSBAR_STYLE, get_library_stylesheet
|
||||||
from openlp.core.version import get_version
|
from openlp.core.version import get_version
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
MEDIA_MANAGER_STYLE = """
|
|
||||||
::tab#media_tool_box {
|
|
||||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
|
||||||
stop: 0 palette(button), stop: 1.0 palette(mid));
|
|
||||||
border: 0;
|
|
||||||
border-radius: 2px;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
/* This is here to make the tabs on KDE with the Breeze theme work */
|
|
||||||
::tab:selected {}
|
|
||||||
"""
|
|
||||||
|
|
||||||
PROGRESSBAR_STYLE = """
|
|
||||||
QProgressBar{
|
|
||||||
height: 10px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class Ui_MainWindow(object):
|
class Ui_MainWindow(object):
|
||||||
"""
|
"""
|
||||||
@ -155,7 +136,7 @@ class Ui_MainWindow(object):
|
|||||||
# Create the MediaManager
|
# Create the MediaManager
|
||||||
self.media_manager_dock = OpenLPDockWidget(main_window, 'media_manager_dock',
|
self.media_manager_dock = OpenLPDockWidget(main_window, 'media_manager_dock',
|
||||||
':/system/system_mediamanager.png')
|
':/system/system_mediamanager.png')
|
||||||
self.media_manager_dock.setStyleSheet(MEDIA_MANAGER_STYLE)
|
self.media_manager_dock.setStyleSheet(get_library_stylesheet())
|
||||||
# Create the media toolbox
|
# Create the media toolbox
|
||||||
self.media_tool_box = QtWidgets.QToolBox(self.media_manager_dock)
|
self.media_tool_box = QtWidgets.QToolBox(self.media_manager_dock)
|
||||||
self.media_tool_box.setObjectName('media_tool_box')
|
self.media_tool_box.setObjectName('media_tool_box')
|
||||||
|
109
openlp/core/ui/style.py
Normal file
109
openlp/core/ui/style.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2017 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; 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
The :mod:`~openlp.core.ui.dark` module looks for and loads a dark theme
|
||||||
|
"""
|
||||||
|
from PyQt5 import QtGui
|
||||||
|
|
||||||
|
from openlp.core.common import is_macosx, is_win
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
|
from openlp.core.common.settings import Settings
|
||||||
|
|
||||||
|
try:
|
||||||
|
import qdarkstyle
|
||||||
|
HAS_DARK_STYLE = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_DARK_STYLE = False
|
||||||
|
|
||||||
|
WIN_REPAIR_STYLESHEET = """
|
||||||
|
QMainWindow::separator
|
||||||
|
{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDockWidget::title
|
||||||
|
{
|
||||||
|
border: 1px solid palette(dark);
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-top: 2px;
|
||||||
|
margin: 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolBar
|
||||||
|
{
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
MEDIA_MANAGER_STYLE = """
|
||||||
|
::tab#media_tool_box {
|
||||||
|
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||||
|
stop: 0 palette(button), stop: 1.0 palette(mid));
|
||||||
|
border: 0;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
/* This is here to make the tabs on KDE with the Breeze theme work */
|
||||||
|
::tab:selected {}
|
||||||
|
"""
|
||||||
|
|
||||||
|
PROGRESSBAR_STYLE = """
|
||||||
|
QProgressBar{
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def get_application_stylesheet():
|
||||||
|
"""
|
||||||
|
Return the correct application stylesheet based on the current style and operating system
|
||||||
|
|
||||||
|
:return str: The correct stylesheet as a string
|
||||||
|
"""
|
||||||
|
stylesheet = ''
|
||||||
|
if HAS_DARK_STYLE and Settings().value('advanced/use_dark_style'):
|
||||||
|
stylesheet = qdarkstyle.load_stylesheet_pyqt5()
|
||||||
|
else:
|
||||||
|
if not Settings().value('advanced/alternate rows'):
|
||||||
|
base_color = Registry().get('application').palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
|
||||||
|
alternate_rows_repair_stylesheet = \
|
||||||
|
'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
|
||||||
|
stylesheet += alternate_rows_repair_stylesheet
|
||||||
|
if is_win():
|
||||||
|
stylesheet += WIN_REPAIR_STYLESHEET
|
||||||
|
return stylesheet
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_stylesheet():
|
||||||
|
"""
|
||||||
|
Return the correct stylesheet for the main window
|
||||||
|
|
||||||
|
:return str: The correct stylesheet as a string
|
||||||
|
"""
|
||||||
|
if not HAS_DARK_STYLE or not Settings().value('advanced/use_dark_style'):
|
||||||
|
return MEDIA_MANAGER_STYLE
|
||||||
|
else:
|
||||||
|
return ''
|
@ -62,7 +62,7 @@ def bibles_service(request):
|
|||||||
|
|
||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
service(request, 'bibles', log)
|
return service(request, 'bibles', log)
|
||||||
|
|
||||||
|
|
||||||
@api_bibles_endpoint.route('bibles/search')
|
@api_bibles_endpoint.route('bibles/search')
|
||||||
@ -95,6 +95,6 @@ def bibles_service_api(request):
|
|||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
search(request, 'bibles', log)
|
return search(request, 'bibles', log)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return {'results': {'items': []}}
|
return {'results': {'items': []}}
|
||||||
|
@ -62,7 +62,7 @@ def custom_service(request):
|
|||||||
|
|
||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
service(request, 'custom', log)
|
return service(request, 'custom', log)
|
||||||
|
|
||||||
|
|
||||||
@api_custom_endpoint.route('custom/search')
|
@api_custom_endpoint.route('custom/search')
|
||||||
@ -95,6 +95,6 @@ def custom_service_api(request):
|
|||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
search(request, 'custom', log)
|
return search(request, 'custom', log)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return {'results': {'items': []}}
|
return {'results': {'items': []}}
|
||||||
|
@ -75,7 +75,7 @@ def images_service(request):
|
|||||||
|
|
||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
service(request, 'images', log)
|
return service(request, 'images', log)
|
||||||
|
|
||||||
|
|
||||||
@api_images_endpoint.route('images/search')
|
@api_images_endpoint.route('images/search')
|
||||||
@ -108,6 +108,6 @@ def images_service_api(request):
|
|||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
search(request, 'images', log)
|
return search(request, 'images', log)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return {'results': {'items': []}}
|
return {'results': {'items': []}}
|
||||||
|
@ -62,7 +62,7 @@ def media_service(request):
|
|||||||
|
|
||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
service(request, 'media', log)
|
return service(request, 'media', log)
|
||||||
|
|
||||||
|
|
||||||
@api_media_endpoint.route('media/search')
|
@api_media_endpoint.route('media/search')
|
||||||
@ -95,6 +95,6 @@ def media_service_api(request):
|
|||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
search(request, 'media', log)
|
return search(request, 'media', log)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return {'results': {'items': []}}
|
return {'results': {'items': []}}
|
||||||
|
@ -76,7 +76,7 @@ def presentations_service(request):
|
|||||||
|
|
||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
service(request, 'presentations', log)
|
return service(request, 'presentations', log)
|
||||||
|
|
||||||
|
|
||||||
@api_presentations_endpoint.route('presentations/search')
|
@api_presentations_endpoint.route('presentations/search')
|
||||||
@ -109,6 +109,6 @@ def presentations_service_api(request):
|
|||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
search(request, 'presentations', log)
|
return search(request, 'presentations', log)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return {'results': {'items': []}}
|
return {'results': {'items': []}}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2017 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; 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 #
|
|
||||||
###############################################################################
|
|
@ -1,155 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2017 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; 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
|
|
||||||
import time
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
|
||||||
|
|
||||||
from openlp.core.api.http import register_endpoint
|
|
||||||
from openlp.core.common import AppLocation, Registry, Settings, OpenLPMixin, UiStrings, check_directory_exists
|
|
||||||
from openlp.core.lib import Plugin, StringContent, translate, build_icon
|
|
||||||
from openlp.plugins.remotes.endpoint import remote_endpoint
|
|
||||||
from openlp.plugins.remotes.deploy import download_and_check, download_sha256
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
__default_settings__ = {
|
|
||||||
'remotes/download version': '0000_00_00'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class RemotesPlugin(Plugin, OpenLPMixin):
|
|
||||||
log.info('Remotes Plugin loaded')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
remotes constructor
|
|
||||||
"""
|
|
||||||
super(RemotesPlugin, self).__init__('remotes', __default_settings__, {})
|
|
||||||
self.icon_path = ':/plugins/plugin_remote.png'
|
|
||||||
self.icon = build_icon(self.icon_path)
|
|
||||||
self.weight = -1
|
|
||||||
register_endpoint(remote_endpoint)
|
|
||||||
Registry().register_function('download_website', self.first_time)
|
|
||||||
Registry().register_function('get_website_version', self.website_version)
|
|
||||||
Registry().set_flag('website_version', '0001_01_01')
|
|
||||||
|
|
||||||
def initialise(self):
|
|
||||||
"""
|
|
||||||
Create the internal file structure if it does not exist
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets')
|
|
||||||
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images')
|
|
||||||
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static')
|
|
||||||
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static', 'index')
|
|
||||||
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def about():
|
|
||||||
"""
|
|
||||||
Information about this plugin
|
|
||||||
"""
|
|
||||||
about_text = translate(
|
|
||||||
'RemotePlugin',
|
|
||||||
'<strong>Web Interface</strong>'
|
|
||||||
'<br />The web interface plugin provides the ability to develop web based interfaces using OpenLP web '
|
|
||||||
'services.\nPredefined interfaces can be download as well as custom developed interfaces.')
|
|
||||||
return about_text
|
|
||||||
|
|
||||||
def set_plugin_text_strings(self):
|
|
||||||
"""
|
|
||||||
Called to define all translatable texts of the plugin
|
|
||||||
"""
|
|
||||||
# Name PluginList
|
|
||||||
self.text_strings[StringContent.Name] = {
|
|
||||||
'singular': translate('RemotePlugin', 'Web Interface', 'name singular'),
|
|
||||||
'plural': translate('RemotePlugin', 'Web Interface', 'name plural')
|
|
||||||
}
|
|
||||||
# Name for MediaDockManager, SettingsManager
|
|
||||||
self.text_strings[StringContent.VisibleName] = {
|
|
||||||
'title': translate('RemotePlugin', 'Web Remote', 'container title')
|
|
||||||
}
|
|
||||||
|
|
||||||
def first_time(self):
|
|
||||||
"""
|
|
||||||
Import web site code if active
|
|
||||||
"""
|
|
||||||
self.application.process_events()
|
|
||||||
progress = Progress(self)
|
|
||||||
progress.forceShow()
|
|
||||||
self.application.process_events()
|
|
||||||
time.sleep(1)
|
|
||||||
download_and_check(progress)
|
|
||||||
self.application.process_events()
|
|
||||||
time.sleep(1)
|
|
||||||
progress.close()
|
|
||||||
self.application.process_events()
|
|
||||||
Settings().setValue('remotes/download version', self.version)
|
|
||||||
|
|
||||||
def website_version(self):
|
|
||||||
"""
|
|
||||||
Download and save the website version and sha256
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
sha256, self.version = download_sha256()
|
|
||||||
Registry().set_flag('website_sha256', sha256)
|
|
||||||
Registry().set_flag('website_version', self.version)
|
|
||||||
|
|
||||||
|
|
||||||
class Progress(QtWidgets.QProgressDialog):
|
|
||||||
"""
|
|
||||||
Local class to handle download display based and supporting httputils:get_web_page
|
|
||||||
"""
|
|
||||||
def __init__(self, parent):
|
|
||||||
super(Progress, self).__init__(parent.main_window)
|
|
||||||
self.parent = parent
|
|
||||||
self.setWindowModality(QtCore.Qt.WindowModal)
|
|
||||||
self.setWindowTitle(translate('RemotePlugin', 'Importing Website'))
|
|
||||||
self.setLabelText(UiStrings().StartingImport)
|
|
||||||
self.setCancelButton(None)
|
|
||||||
self.setRange(0, 1)
|
|
||||||
self.setMinimumDuration(0)
|
|
||||||
self.was_cancelled = False
|
|
||||||
self.previous_size = 0
|
|
||||||
|
|
||||||
def _download_progress(self, count, block_size):
|
|
||||||
"""
|
|
||||||
Calculate and display the download progress.
|
|
||||||
"""
|
|
||||||
increment = (count * block_size) - self.previous_size
|
|
||||||
self._increment_progress_bar(None, increment)
|
|
||||||
self.previous_size = count * block_size
|
|
||||||
|
|
||||||
def _increment_progress_bar(self, status_text, increment=1):
|
|
||||||
"""
|
|
||||||
Update the wizard progress page.
|
|
||||||
|
|
||||||
:param status_text: Current status information to display.
|
|
||||||
:param increment: The value to increment the progress bar by.
|
|
||||||
"""
|
|
||||||
if status_text:
|
|
||||||
self.setText(status_text)
|
|
||||||
if increment > 0:
|
|
||||||
self.setValue(self.value() + increment)
|
|
||||||
self.parent.application.process_events()
|
|
@ -62,7 +62,7 @@ def songs_service(request):
|
|||||||
|
|
||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
service(request, 'songs', log)
|
return service(request, 'songs', log)
|
||||||
|
|
||||||
|
|
||||||
@api_songs_endpoint.route('songs/search')
|
@api_songs_endpoint.route('songs/search')
|
||||||
@ -95,6 +95,6 @@ def songs_service_api(request):
|
|||||||
:param request: The http request object.
|
:param request: The http request object.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
search(request, 'songs', log)
|
return service(request, 'songs', log)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return {'results': {'items': []}}
|
return {'results': {'items': []}}
|
||||||
|
@ -22,14 +22,12 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from openlp.plugins.remotes.deploy import deploy_zipfile
|
from openlp.core.api.deploy import deploy_zipfile
|
||||||
|
|
||||||
|
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
|
||||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
|
|
||||||
|
|
||||||
|
|
||||||
class TestRemoteDeploy(TestCase):
|
class TestRemoteDeploy(TestCase):
|
||||||
@ -54,6 +52,7 @@ class TestRemoteDeploy(TestCase):
|
|||||||
Remote Deploy tests - test the dummy zip file is processed correctly
|
Remote Deploy tests - test the dummy zip file is processed correctly
|
||||||
"""
|
"""
|
||||||
# GIVEN: A new downloaded zip file
|
# GIVEN: A new downloaded zip file
|
||||||
|
aa = TEST_PATH
|
||||||
zip_file = os.path.join(TEST_PATH, 'remotes', 'site.zip')
|
zip_file = os.path.join(TEST_PATH, 'remotes', 'site.zip')
|
||||||
app_root = os.path.join(self.app_root, 'site.zip')
|
app_root = os.path.join(self.app_root, 'site.zip')
|
||||||
shutil.copyfile(zip_file, app_root)
|
shutil.copyfile(zip_file, app_root)
|
111
tests/functional/openlp_core_ui/test_style.py
Normal file
111
tests/functional/openlp_core_ui/test_style.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2017 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; 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Package to test the :mod:`~openlp.core.ui.style` module.
|
||||||
|
"""
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
import openlp.core.ui.style
|
||||||
|
from openlp.core.ui.style import MEDIA_MANAGER_STYLE, WIN_REPAIR_STYLESHEET, get_application_stylesheet, \
|
||||||
|
get_library_stylesheet
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.ui.style.HAS_DARK_STYLE', True)
|
||||||
|
@patch('openlp.core.ui.style.Settings')
|
||||||
|
@patch.object(openlp.core.ui.style, 'qdarkstyle')
|
||||||
|
def test_get_application_stylesheet_dark(mocked_qdarkstyle, MockSettings):
|
||||||
|
"""Test that the dark stylesheet is returned when available and enabled"""
|
||||||
|
# GIVEN: We're on Windows and no dark style is set
|
||||||
|
mocked_settings = MagicMock()
|
||||||
|
mocked_settings.value.return_value = True
|
||||||
|
MockSettings.return_value = mocked_settings
|
||||||
|
mocked_qdarkstyle.load_stylesheet_pyqt5.return_value = 'dark_style'
|
||||||
|
|
||||||
|
# WHEN: can_show_icon() is called
|
||||||
|
result = get_application_stylesheet()
|
||||||
|
|
||||||
|
# THEN: the result should be false
|
||||||
|
assert result == 'dark_style'
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.ui.style.HAS_DARK_STYLE', False)
|
||||||
|
@patch('openlp.core.ui.style.is_win')
|
||||||
|
@patch('openlp.core.ui.style.Settings')
|
||||||
|
@patch('openlp.core.ui.style.Registry')
|
||||||
|
def test_get_application_stylesheet_not_alternate_rows(MockRegistry, MockSettings, mocked_is_win):
|
||||||
|
"""Test that the alternate rows stylesheet is returned when enabled in settings"""
|
||||||
|
# GIVEN: We're on Windows and no dark style is set
|
||||||
|
mocked_is_win.return_value = False
|
||||||
|
MockSettings.return_value.value.return_value = False
|
||||||
|
MockRegistry.return_value.get.return_value.palette.return_value.color.return_value.name.return_value = 'color'
|
||||||
|
|
||||||
|
# WHEN: can_show_icon() is called
|
||||||
|
result = get_application_stylesheet()
|
||||||
|
|
||||||
|
# THEN: the result should be false
|
||||||
|
MockSettings.return_value.value.assert_called_once_with('advanced/alternate rows')
|
||||||
|
assert result == 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: color;}\n', result
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.ui.style.HAS_DARK_STYLE', False)
|
||||||
|
@patch('openlp.core.ui.style.is_win')
|
||||||
|
@patch('openlp.core.ui.style.Settings')
|
||||||
|
def test_get_application_stylesheet_win_repair(MockSettings, mocked_is_win):
|
||||||
|
"""Test that the Windows repair stylesheet is returned when on Windows"""
|
||||||
|
# GIVEN: We're on Windows and no dark style is set
|
||||||
|
mocked_is_win.return_value = True
|
||||||
|
MockSettings.return_value.value.return_value = True
|
||||||
|
|
||||||
|
# WHEN: can_show_icon() is called
|
||||||
|
result = get_application_stylesheet()
|
||||||
|
|
||||||
|
# THEN: the result should be false
|
||||||
|
MockSettings.return_value.value.assert_called_once_with('advanced/alternate rows')
|
||||||
|
assert result == WIN_REPAIR_STYLESHEET
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.ui.style.HAS_DARK_STYLE', False)
|
||||||
|
@patch('openlp.core.ui.style.Settings')
|
||||||
|
def test_get_library_stylesheet_no_dark_style(MockSettings):
|
||||||
|
"""Test that the media manager stylesheet is returned when there's no dark theme available"""
|
||||||
|
# GIVEN: No dark style
|
||||||
|
MockSettings.return_value.value.return_value = False
|
||||||
|
|
||||||
|
# WHEN: get_library_stylesheet() is called
|
||||||
|
result = get_library_stylesheet()
|
||||||
|
|
||||||
|
# THEN: The correct stylesheet should be returned
|
||||||
|
assert result == MEDIA_MANAGER_STYLE
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.core.ui.style.HAS_DARK_STYLE', True)
|
||||||
|
@patch('openlp.core.ui.style.Settings')
|
||||||
|
def test_get_library_stylesheet_dark_style(MockSettings):
|
||||||
|
"""Test that no stylesheet is returned when the dark theme is enabled"""
|
||||||
|
# GIVEN: No dark style
|
||||||
|
MockSettings.return_value.value.return_value = True
|
||||||
|
|
||||||
|
# WHEN: get_library_stylesheet() is called
|
||||||
|
result = get_library_stylesheet()
|
||||||
|
|
||||||
|
# THEN: The correct stylesheet should be returned
|
||||||
|
assert result == ''
|
@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2017 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; 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 #
|
|
||||||
###############################################################################
|
|
@ -94,4 +94,3 @@ class TestPluginManager(TestCase, TestMixin):
|
|||||||
self.assertIn('custom', plugin_names, 'There should be a "custom" plugin')
|
self.assertIn('custom', plugin_names, 'There should be a "custom" plugin')
|
||||||
self.assertIn('songusage', plugin_names, 'There should be a "songusage" plugin')
|
self.assertIn('songusage', plugin_names, 'There should be a "songusage" plugin')
|
||||||
self.assertIn('alerts', plugin_names, 'There should be a "alerts" plugin')
|
self.assertIn('alerts', plugin_names, 'There should be a "alerts" plugin')
|
||||||
self.assertIn('remotes', plugin_names, 'There should be a "remotes" plugin')
|
|
||||||
|
Loading…
Reference in New Issue
Block a user