From 51ab25b716d87058dc4223a4bb182dcb7d5d0b84 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 11 Jul 2013 21:54:30 +0100 Subject: [PATCH 1/5] Fix the constraints to be > 1 Fixes: https://launchpad.net/bugs/1196926 --- openlp/core/ui/generaltab.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index 49497a10e..7fe7beaca 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -93,14 +93,14 @@ class GeneralTab(SettingsTab): self.monitor_layout.addWidget(self.custom_width_label, 3, 3) self.custom_width_value_edit = QtGui.QSpinBox(self.monitor_group_box) self.custom_width_value_edit.setObjectName(u'custom_width_value_edit') - self.custom_width_value_edit.setMaximum(9999) + self.custom_width_value_edit.setRange(1, 9999) self.monitor_layout.addWidget(self.custom_width_value_edit, 4, 3) self.custom_height_label = QtGui.QLabel(self.monitor_group_box) self.custom_height_label.setObjectName(u'custom_height_label') self.monitor_layout.addWidget(self.custom_height_label, 3, 4) self.custom_height_value_edit = QtGui.QSpinBox(self.monitor_group_box) self.custom_height_value_edit.setObjectName(u'custom_height_value_edit') - self.custom_height_value_edit.setMaximum(9999) + self.custom_height_value_edit.setRange(1, 9999) self.monitor_layout.addWidget(self.custom_height_value_edit, 4, 4) self.display_on_monitor_check = QtGui.QCheckBox(self.monitor_group_box) self.display_on_monitor_check.setObjectName(u'monitor_combo_box') From 6062605622aa44b6b4a5261ad44fc40e892e8bef Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 11 Jul 2013 21:58:15 +0100 Subject: [PATCH 2/5] make sure we have the image file for theme backgrounds Fixes: https://launchpad.net/bugs/1197376 --- openlp/core/ui/themeform.py | 4 ++-- openlp/core/utils/__init__.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 68d8cc216..007932f6e 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -38,7 +38,7 @@ from openlp.core.lib import UiStrings, Registry, translate from openlp.core.lib.theme import BackgroundType, BackgroundGradientType from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui import ThemeLayoutForm -from openlp.core.utils import get_images_filter +from openlp.core.utils import get_images_filter, is_not_image_file from themewizard import Ui_ThemeWizard log = logging.getLogger(__name__) @@ -178,7 +178,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): """ background_image = BackgroundType.to_string(BackgroundType.Image) if self.page(self.currentId()) == self.backgroundPage and \ - self.theme.background_type == background_image and not self.imageFileEdit.text(): + self.theme.background_type == background_image and is_not_image_file(self.imageFileEdit.text()): QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'), translate('OpenLP.ThemeWizard', 'You have not selected a ' 'background image. Please select one before continuing.')) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index bfd0b0740..fb06332f3 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -246,6 +246,23 @@ def get_images_filter(): return IMAGES_FILTER +def is_not_image_file(file_name): + """ + Validate that the file is not an image file. + + ``file_name`` + File name to be checked. + """ + if file_name.isEmpty(): + return True + else: + formats = [fmt.lower() for fmt in QtGui.QImageReader.supportedImageFormats()] + file_part, file_extension = os.path.splitext(unicode(file_name)) + if file_extension[1:].lower() in formats and os.path.exists(file_name): + return False + return True + + def split_filename(path): """ Return a list of the parts in a given path. From 6e7700d8fd262f2126ca6ca66f396d2ed2909de5 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 12 Jul 2013 19:13:06 +0100 Subject: [PATCH 3/5] rename url from live to main --- .../remotes/html/{live.css => main.css} | 0 .../remotes/html/{live.html => main.html} | 4 +- .../plugins/remotes/html/{live.js => main.js} | 4 +- openlp/plugins/remotes/lib/httpserver.py | 40 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) rename openlp/plugins/remotes/html/{live.css => main.css} (100%) rename openlp/plugins/remotes/html/{live.html => main.html} (95%) rename openlp/plugins/remotes/html/{live.js => main.js} (98%) diff --git a/openlp/plugins/remotes/html/live.css b/openlp/plugins/remotes/html/main.css similarity index 100% rename from openlp/plugins/remotes/html/live.css rename to openlp/plugins/remotes/html/main.css diff --git a/openlp/plugins/remotes/html/live.html b/openlp/plugins/remotes/html/main.html similarity index 95% rename from openlp/plugins/remotes/html/live.html rename to openlp/plugins/remotes/html/main.html index f9a2c874c..3fbd42447 100644 --- a/openlp/plugins/remotes/html/live.html +++ b/openlp/plugins/remotes/html/main.html @@ -30,10 +30,10 @@ ${live_title} - + - + diff --git a/openlp/plugins/remotes/html/live.js b/openlp/plugins/remotes/html/main.js similarity index 98% rename from openlp/plugins/remotes/html/live.js rename to openlp/plugins/remotes/html/main.js index d55072c16..4f4f36351 100644 --- a/openlp/plugins/remotes/html/live.js +++ b/openlp/plugins/remotes/html/main.js @@ -26,7 +26,7 @@ window.OpenLP = { loadSlide: function (event) { $.getJSON( - "/live/image", + "/main/image", function (data, status) { var img = document.getElementById('image'); img.src = data.results.slide_image; @@ -36,7 +36,7 @@ window.OpenLP = { }, pollServer: function () { $.getJSON( - "/live/poll", + "/main/poll", function (data, status) { if (OpenLP.slideCount != data.results.slide_count) { OpenLP.slideCount = data.results.slide_count; diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index a2abbb41e..ac68c2e24 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -177,11 +177,11 @@ class HttpServer(object): self.root = self.Public() self.root.files = self.Files() self.root.stage = self.Stage() - self.root.live = self.Live() + self.root.main = self.Main() self.root.router = self.router self.root.files.router = self.router self.root.stage.router = self.router - self.root.live.router = self.router + self.root.main.router = self.router cherrypy.tree.mount(self.root, '/', config=self.define_config()) # Turn off the flood of access messages cause by poll cherrypy.log.access_log.propagate = False @@ -218,7 +218,7 @@ class HttpServer(object): u'/stage': {u'tools.staticdir.on': True, u'tools.staticdir.dir': self.router.html_dir, u'tools.basic_auth.on': False}, - u'/live': {u'tools.staticdir.on': True, + u'/main': {u'tools.staticdir.on': True, u'tools.staticdir.dir': self.router.html_dir, u'tools.basic_auth.on': False}} return directory_config @@ -253,9 +253,9 @@ class HttpServer(object): url = urlparse.urlparse(cherrypy.url()) return self.router.process_http_request(url.path, *args) - class Live(object): + class Main(object): """ - Live view is read only so security is not relevant and would reduce it's usability + Main view is read only so security is not relevant and would reduce it's usability """ @cherrypy.expose def default(self, *args, **kwargs): @@ -281,12 +281,12 @@ class HttpRouter(object): self.routes = [ (u'^/$', self.serve_file), (u'^/(stage)$', self.serve_file), - (u'^/(live)$', self.serve_file), + (u'^/(main)$', self.serve_file), (r'^/files/(.*)$', self.serve_file), (r'^/api/poll$', self.poll), (r'^/stage/poll$', self.poll), - (r'^/live/poll$', self.live_poll), - (r'^/live/image$', self.live_image), + (r'^/main/poll$', self.main_poll), + (r'^/main/image$', self.main_image), (r'^/api/controller/(live|preview)/(.*)$', self.controller), (r'^/stage/controller/(live|preview)/(.*)$', self.controller), (r'^/api/service/(.*)$', self.service), @@ -378,7 +378,7 @@ class HttpRouter(object): 'slides': translate('RemotePlugin.Mobile', 'Slides') } - def serve_file(self, filename=None): + def serve_file(self, file_name=None): """ Send a file to the socket. For now, just a subset of file types and must be top level inside the html folder. If subfolders requested return 404, easier for security for the present. @@ -386,17 +386,17 @@ class HttpRouter(object): Ultimately for i18n, this could first look for xx/file.html before falling back to file.html. where xx is the language, e.g. 'en' """ - log.debug(u'serve file request %s' % filename) - if not filename: - filename = u'index.html' - elif filename == u'stage': - filename = u'stage.html' - elif filename == u'live': - filename = u'live.html' - path = os.path.normpath(os.path.join(self.html_dir, filename)) + log.debug(u'serve file request %s' % file_name) + if not file_name: + file_name = u'index.html' + elif file_name == u'stage': + file_name = u'stage.html' + elif file_name == u'main': + file_name = u'main.html' + path = os.path.normpath(os.path.join(self.html_dir, file_name)) if not path.startswith(self.html_dir): return self._http_not_found() - ext = os.path.splitext(filename)[1] + ext = os.path.splitext(file_name)[1] html = None if ext == u'.html': mimetype = u'text/html' @@ -447,7 +447,7 @@ class HttpRouter(object): cherrypy.response.headers['Content-Type'] = u'application/json' return json.dumps({u'results': result}) - def live_poll(self): + def main_poll(self): """ Poll OpenLP to determine the current slide count. """ @@ -457,7 +457,7 @@ class HttpRouter(object): cherrypy.response.headers['Content-Type'] = u'application/json' return json.dumps({u'results': result}) - def live_image(self): + def main_image(self): """ Return the latest display image as a byte stream. """ From 94e8b90c5d3679fed4aacf44b7dad6c7e7eacfed Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 13 Jul 2013 17:33:32 +0100 Subject: [PATCH 4/5] Added first test --- openlp/core/utils/__init__.py | 4 +-- .../interfaces/openlp_core_utils/__init__.py | 0 .../openlp_core_utils/test_utils.py | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/interfaces/openlp_core_utils/__init__.py create mode 100644 tests/interfaces/openlp_core_utils/test_utils.py diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index fb06332f3..843849f63 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -253,10 +253,10 @@ def is_not_image_file(file_name): ``file_name`` File name to be checked. """ - if file_name.isEmpty(): + if not file_name: return True else: - formats = [fmt.lower() for fmt in QtGui.QImageReader.supportedImageFormats()] + formats = [unicode(fmt).lower() for fmt in QtGui.QImageReader.supportedImageFormats()] file_part, file_extension = os.path.splitext(unicode(file_name)) if file_extension[1:].lower() in formats and os.path.exists(file_name): return False diff --git a/tests/interfaces/openlp_core_utils/__init__.py b/tests/interfaces/openlp_core_utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/interfaces/openlp_core_utils/test_utils.py b/tests/interfaces/openlp_core_utils/test_utils.py new file mode 100644 index 000000000..b4b4c2bc9 --- /dev/null +++ b/tests/interfaces/openlp_core_utils/test_utils.py @@ -0,0 +1,29 @@ +""" +Functional tests to test the AppLocation class and related methods. +""" +from unittest import TestCase + +from mock import patch +from PyQt4 import QtCore + + +from openlp.core.utils import is_not_image_file +from tests.utils.constants import TEST_RESOURCES_PATH + + +class TestUtils(TestCase): + """ + A test suite to test out various methods around the Utils functions. + """ + def is_not_image_empty_test(self): + """ + Test the method handles an empty string + """ + # Given and empty string + file_name = "" + + # WHEN testing for it + result = is_not_image_file(file_name) + + # THEN the result is false + assert result is True, u'The missing file test should return True' From 3f1d2c1c2108f8bd7745423e048e5c66aa287c66 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 14 Jul 2013 06:56:11 +0100 Subject: [PATCH 5/5] Fix up tests --- .../openlp_core_utils/test_utils.py | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tests/interfaces/openlp_core_utils/test_utils.py b/tests/interfaces/openlp_core_utils/test_utils.py index b4b4c2bc9..fe5d33560 100644 --- a/tests/interfaces/openlp_core_utils/test_utils.py +++ b/tests/interfaces/openlp_core_utils/test_utils.py @@ -1,12 +1,9 @@ """ Functional tests to test the AppLocation class and related methods. """ +import os from unittest import TestCase -from mock import patch -from PyQt4 import QtCore - - from openlp.core.utils import is_not_image_file from tests.utils.constants import TEST_RESOURCES_PATH @@ -27,3 +24,29 @@ class TestUtils(TestCase): # THEN the result is false assert result is True, u'The missing file test should return True' + + def is_not_image_with_image_file_test(self): + """ + Test the method handles an image file + """ + # Given and empty string + file_name = os.path.join(TEST_RESOURCES_PATH, u'church.jpg') + + # WHEN testing for it + result = is_not_image_file(file_name) + + # THEN the result is false + assert result is False, u'The file is present so the test should return False' + + def is_not_image_with_none_image_file_test(self): + """ + Test the method handles a non image file + """ + # Given and empty string + file_name = os.path.join(TEST_RESOURCES_PATH, u'serviceitem_custom_1.osj') + + # WHEN testing for it + result = is_not_image_file(file_name) + + # THEN the result is false + assert result is True, u'The file is not an image file so the test should return True' \ No newline at end of file