From 04abbd97d018f56054f8eccf8b3eaa15f29993aa Mon Sep 17 00:00:00 2001 From: Felipe Polo-Wood Date: Fri, 22 Nov 2013 13:21:07 -0500 Subject: [PATCH] implemented caching thru the ImageManager Styling issues Merge with fix-router changes --- .bzrignore | 60 ++++----- openlp/core/common/applocation.py | 4 +- openlp/core/lib/__init__.py | 3 +- openlp/core/lib/serviceitem.py | 12 +- openlp/core/ui/slidecontroller.py | 3 +- .../presentations/lib/pptviewlib/ppttest.py | 47 ------- openlp/plugins/remotes/html/openlp.js | 2 +- openlp/plugins/remotes/lib/httprouter.py | 33 +++-- .../openlp_core_lib/test_serviceitem.py | 127 +++++++++--------- .../openlp_plugins/remotes/test_router.py | 54 +++++++- 10 files changed, 168 insertions(+), 177 deletions(-) diff --git a/.bzrignore b/.bzrignore index d87c55a61..32e9d2089 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,30 +1,30 @@ -*.pyc -*.*~ -\#*\# -*.eric4project -*.ropeproject -*.e4* -.eric4project -list -openlp.org 2.0.e4* -documentation/build/html -documentation/build/doctrees -*.log* -dist -OpenLP.egg-info -build -resources/innosetup/Output -_eric4project -.pylint.d -*.qm -openlp/core/resources.py.old -*.qm -resources/windows/warnOpenLP.txt -openlp.cfg -.idea -openlp.pro -.kdev4 -tests.kdev4 -*.nja -*.orig -__pycache__ +*.pyc +*.*~ +\#*\# +*.eric4project +*.ropeproject +*.e4* +.eric4project +list +openlp.org 2.0.e4* +documentation/build/html +documentation/build/doctrees +*.log* +dist +OpenLP.egg-info +build +resources/innosetup/Output +_eric4project +.pylint.d +*.qm +openlp/core/resources.py.old +*.qm +resources/windows/warnOpenLP.txt +openlp.cfg +.idea +openlp.pro +.kdev4 +tests.kdev4 +*.nja +*.orig +__pycache__ \ No newline at end of file diff --git a/openlp/core/common/applocation.py b/openlp/core/common/applocation.py index 41b47ecbe..8a298f925 100644 --- a/openlp/core/common/applocation.py +++ b/openlp/core/common/applocation.py @@ -76,8 +76,8 @@ class AppLocation(object): return get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0]) elif dir_type == AppLocation.PluginsDir: app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) - return get_frozen_path(os.path.join(app_path, 'plugins'), - os.path.join(os.path.split(openlp.__file__)[0], 'plugins')) + return os.path.normpath(get_frozen_path(os.path.join(app_path, 'plugins'), + os.path.join(os.path.split(openlp.__file__)[0], 'plugins'))) elif dir_type == AppLocation.VersionDir: return get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0]) elif dir_type == AppLocation.LanguageDir: diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 0793e0644..712e3a0fb 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -152,8 +152,7 @@ def image_to_byte(image, base_64=True): The image to converted. ``base_64`` - If True returns the image as Base64 bytes, otherwise - the image is returned as a byte array + If True returns the image as Base64 bytes, otherwise the image is returned as a byte array To preserve original intention, this defaults to True """ log.debug('image_to_byte - start') diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 8931867c2..3db9789eb 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -331,8 +331,8 @@ class ServiceItem(object): The command of/for the slide. """ self.service_item_type = ServiceItemType.Command - self._raw_frames.append({'title': file_name, 'image': image, - 'path': path, 'display_title': display_title, 'notes': notes}) + self._raw_frames.append({'title': file_name, 'image': image, 'path': path, + 'display_title': display_title, 'notes': notes}) self._new_item() def get_service_repr(self, lite_save): @@ -451,12 +451,10 @@ class ServiceItem(object): self.title = text_image['title'] if path: self.has_original_files = False - self.add_from_command(path, text_image['title'], - text_image['image'], text_image.get('display_title',''), - text_image.get('notes', '')) + self.add_from_command(path, text_image['title'], text_image['image'], + text_image.get('display_title',''), text_image.get('notes', '')) else: - self.add_from_command(text_image['path'], - text_image['title'], text_image['image']) + self.add_from_command(text_image['path'], text_image['title'], text_image['image']) self._new_item() def get_display_title(self): diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index a2299ad54..5a588f1a6 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -815,8 +815,7 @@ class SlideController(DisplayController): if not self.service_item: return if self.service_item.is_command(): - Registry().execute('%s_slide' % self.service_item.name.lower(), - [self.service_item, self.is_live, index]) + Registry().execute('%s_slide' % self.service_item.name.lower(), [self.service_item, self.is_live, index]) self.update_preview() self.selected_row = index else: diff --git a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py index a8f093845..6931cee6f 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py +++ b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py @@ -28,9 +28,6 @@ ############################################################################### import sys -import zipfile -import re -from xml.etree import ElementTree from PyQt4 import QtGui, QtCore from ctypes import * from ctypes.wintypes import RECT @@ -177,50 +174,6 @@ class PPTViewer(QtGui.QWidget): int(self.widthEdit.text()), int(self.heightEdit.text())) filename = str(self.pptEdit.text().replace('/', '\\')) folder = str(self.folderEdit.text().replace('/', '\\')) - if zipfile.is_zipfile(filename): - namespaces = {"p": - "http://schemas.openxmlformats.org/presentationml/2006/main", - "a": "http://schemas.openxmlformats.org/drawingml/2006/main"} - with zipfile.ZipFile(filename) as zip_file: - with zip_file.open('ppt/presentation.xml') as pres: - tree = ElementTree.parse(pres) - nodes = tree.getroot().findall(".//p:sldIdLst/p:sldId", - namespaces=namespaces) - print ("slide count: " + str(len(nodes))) - titles = [None for i in range(len(nodes))] - notes = [None for i in range(len(nodes))] - for zip_info in zip_file.infolist(): - nodeType = '' - index = -1 - listToAdd = None - match = re.search("slides/slide(.+)\.xml", - zip_info.filename) - if match: - index = int(match.group(1))-1 - nodeType = 'ctrTitle' - listToAdd = titles - match = re.search("notesSlides/notesSlide(.+)\.xml", - zip_info.filename) - if match: - index = int(match.group(1))-1 - nodeType = 'body' - listToAdd = notes - if len(nodeType)>0: - with zip_file.open(zip_info) as zipped_file: - tree = ElementTree.parse(zipped_file) - text = '' - nodes = tree.getroot().findall(".//p:ph[@type='" + \ - nodeType + "']../../..//p:txBody//a:t", - namespaces=namespaces) - if nodes and len(nodes)>0: - for node in nodes: - if len(text) > 0: - text += '\n' - text += node.text - print('slide file: ' + zip_info.filename + ' ' + text) - listToAdd[index] = text - print(titles) - print(notes) print(filename, folder) self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder) print('id: ' + str(self.pptid)) diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 448fbb269..86c10af07 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -398,5 +398,5 @@ $.ajaxSetup({cache: false}); $("#search").live("pageinit", function (event) { OpenLP.getSearchablePlugins(); }); -setInterval("OpenLP.pollServer();", 500); +setInterval("OpenLP.pollServer();", 50000); OpenLP.pollServer(); diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 94be82c12..4c4b76bfc 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -124,11 +124,19 @@ from urllib.parse import urlparse, parse_qs from mako.template import Template from PyQt4 import QtCore -from openlp.core.lib import Registry, PluginStatus, StringContent, image_to_byte, resize_image, ItemCapabilities -from openlp.core.utils import AppLocation, translate -from openlp.core.common import Settings +from openlp.core.common import AppLocation, Settings, translate +from openlp.core.lib import Registry, PluginStatus, StringContent, image_to_byte log = logging.getLogger(__name__) +FILE_TYPES = { + '.html': 'text/html', + '.css': 'text/css', + '.js': 'application/javascript', + '.jpg': 'image/jpeg', + '.gif': 'image/gif', + '.ico': 'image/x-icon', + '.png': 'image/png' +} class HttpRouter(object): @@ -350,13 +358,12 @@ class HttpRouter(object): if not path.startswith(self.html_dir): return self.do_not_found() content = None - ext, content_type = self.get_content_type(file_name) + ext, content_type = self.get_content_type(path) file_handle = None try: if ext == '.html': variables = self.template_vars - content = Template(filename=path, input_encoding='utf-8', - output_encoding='utf-8').render(**variables) + content = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables) else: file_handle = open(path, 'rb') log.debug('Opened %s' % path) @@ -375,20 +382,12 @@ class HttpRouter(object): def get_content_type(self, file_name): """ Examines the extension of the file and determines - what header to send back - Returns the extension found + what the content_type should be, defaults to text/plain + Returns the extension and the content_type """ content_type = 'text/plain' - file_types = {'.html': 'text/html', - '.css': 'text/css', - '.js': 'application/javascript', - '.jpg': 'image/jpeg', - '.gif': 'image/gif', - '.ico': 'image/x-icon', - '.png': 'image/png' - } ext = os.path.splitext(file_name)[1] - content_type = file_types.get(ext, 'text/plain') + content_type = FILE_TYPES.get(ext, 'text/plain') return ext, content_type def serve_thumbnail(self, controller_name=None, dimensions=None, file_name=None): diff --git a/tests/functional/openlp_core_lib/test_serviceitem.py b/tests/functional/openlp_core_lib/test_serviceitem.py index 577e436c0..2d1d7e85b 100644 --- a/tests/functional/openlp_core_lib/test_serviceitem.py +++ b/tests/functional/openlp_core_lib/test_serviceitem.py @@ -35,8 +35,7 @@ from unittest import TestCase from tests.functional import MagicMock, patch from tests.utils import assert_length, convert_file_service_item -from openlp.core.lib import ItemCapabilities, ServiceItem, Registry, \ - ServiceItemType +from openlp.core.lib import ItemCapabilities, ServiceItem, Registry, ServiceItemType VERSE = 'The Lord said to {r}Noah{/r}: \n'\ @@ -123,28 +122,28 @@ class TestServiceItem(TestCase): mocked_exists.return_value = True service_item.set_from_service(line, TEST_PATH) - # THEN: We should get back a valid service item - self.assertTrue(service_item.is_valid, 'The new service item should be valid') - self.assertEqual(os.path.normpath(test_file), - os.path.normpath(service_item.get_rendered_frame(0)), - 'The first frame should match the path to the image') - self.assertEqual(frame_array, service_item.get_frames()[0], - 'The return should match frame array1') - self.assertEqual(test_file, service_item.get_frame_path(0), - 'The frame path should match the full path to the image') - self.assertEqual(image_name, service_item.get_frame_title(0), - 'The frame title should match the image name') - self.assertEqual(image_name, service_item.get_display_title(), - 'The display title should match the first image name') - self.assertTrue(service_item.is_image(), 'This service item should be of an "image" type') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanMaintain), - 'This service item should be able to be Maintained') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanPreview), - 'This service item should be able to be be Previewed') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanLoop), - 'This service item should be able to be run in a can be made to Loop') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), - 'This service item should be able to have new items added to it') + # THEN: We should get back a valid service item + self.assertTrue(service_item.is_valid, 'The new service item should be valid') + self.assertEqual(os.path.normpath(test_file), + os.path.normpath(service_item.get_rendered_frame(0)), + 'The first frame should match the path to the image') + self.assertEqual(frame_array, service_item.get_frames()[0], + 'The return should match frame array1') + self.assertEqual(test_file, service_item.get_frame_path(0), + 'The frame path should match the full path to the image') + self.assertEqual(image_name, service_item.get_frame_title(0), + 'The frame title should match the image name') + self.assertEqual(image_name, service_item.get_display_title(), + 'The display title should match the first image name') + self.assertTrue(service_item.is_image(), 'This service item should be of an "image" type') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanMaintain), + 'This service item should be able to be Maintained') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanPreview), + 'This service item should be able to be be Previewed') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanLoop), + 'This service item should be able to be run in a can be made to Loop') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), + 'This service item should be able to have new items added to it') def service_item_load_image_from_local_service_test(self): """ @@ -153,10 +152,8 @@ class TestServiceItem(TestCase): # GIVEN: A new service item and a mocked add icon function image_name1 = 'image_1.jpg' image_name2 = 'image_2.jpg' - test_file1 = os.path.normpath(os.path.join('/home/openlp', - image_name1)) - test_file2 = os.path.normpath(os.path.join('/home/openlp', - image_name2)) + test_file1 = os.path.normpath(os.path.join('/home/openlp', image_name1)) + test_file2 = os.path.normpath(os.path.join('/home/openlp', image_name2)) frame_array1 = {'path': test_file1, 'title': image_name1} frame_array2 = {'path': test_file2, 'title': image_name2} @@ -175,44 +172,44 @@ class TestServiceItem(TestCase): service_item2.set_from_service(line2) service_item.set_from_service(line) - # THEN: We should get back a valid service item + # THEN: We should get back a valid service item - # This test is copied from service_item.py, but is changed since to conform to - # new layout of service item. The layout use in serviceitem_image_2.osd is actually invalid now. - self.assertTrue(service_item.is_valid, 'The first service item should be valid') - self.assertTrue(service_item2.is_valid, 'The second service item should be valid') - self.assertEqual(test_file1, - os.path.normpath(service_item.get_rendered_frame(0)), - 'The first frame should match the path to the image') - self.assertEqual(test_file2, - os.path.normpath(service_item2.get_rendered_frame(0)), - 'The Second frame should match the path to the image') - # There is a problem with the following two asserts in Windows - # and it is not easily fixable (although it looks simple) - if os.name != 'nt': - self.assertEqual(frame_array1, service_item.get_frames()[0], 'The return should match the frame array1') - self.assertEqual(frame_array2, service_item2.get_frames()[0], 'The return should match the frame array2') - self.assertEqual(test_file1, os.path.normpath( - service_item.get_frame_path(0)), - 'The frame path should match the full path to the image') - self.assertEqual(test_file2, os.path.normpath( - service_item2.get_frame_path(0)), - 'The frame path should match the full path to the image') - self.assertEqual(image_name1, service_item.get_frame_title(0), - 'The 1st frame title should match the image name') - self.assertEqual(image_name2, service_item2.get_frame_title(0), - 'The 2nd frame title should match the image name') - self.assertEqual(service_item.name, service_item.title.lower(), - 'The plugin name should match the display title, as there are > 1 Images') - self.assertTrue(service_item.is_image(), 'This service item should be of an "image" type') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanMaintain), - 'This service item should be able to be Maintained') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanPreview), - 'This service item should be able to be be Previewed') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanLoop), - 'This service item should be able to be run in a can be made to Loop') - self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), - 'This service item should be able to have new items added to it') + # This test is copied from service_item.py, but is changed since to conform to + # new layout of service item. The layout use in serviceitem_image_2.osd is actually invalid now. + self.assertTrue(service_item.is_valid, 'The first service item should be valid') + self.assertTrue(service_item2.is_valid, 'The second service item should be valid') + self.assertEqual(test_file1, + os.path.normpath(service_item.get_rendered_frame(0)), + 'The first frame should match the path to the image') + self.assertEqual(test_file2, + os.path.normpath(service_item2.get_rendered_frame(0)), + 'The Second frame should match the path to the image') + # There is a problem with the following two asserts in Windows + # and it is not easily fixable (although it looks simple) + if os.name != 'nt': + self.assertEqual(frame_array1, service_item.get_frames()[0], 'The return should match the frame array1') + self.assertEqual(frame_array2, service_item2.get_frames()[0], 'The return should match the frame array2') + self.assertEqual(test_file1, os.path.normpath( + service_item.get_frame_path(0)), + 'The frame path should match the full path to the image') + self.assertEqual(test_file2, os.path.normpath( + service_item2.get_frame_path(0)), + 'The frame path should match the full path to the image') + self.assertEqual(image_name1, service_item.get_frame_title(0), + 'The 1st frame title should match the image name') + self.assertEqual(image_name2, service_item2.get_frame_title(0), + 'The 2nd frame title should match the image name') + self.assertEqual(service_item.name, service_item.title.lower(), + 'The plugin name should match the display title, as there are > 1 Images') + self.assertTrue(service_item.is_image(), 'This service item should be of an "image" type') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanMaintain), + 'This service item should be able to be Maintained') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanPreview), + 'This service item should be able to be be Previewed') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanLoop), + 'This service item should be able to be run in a can be made to Loop') + self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), + 'This service item should be able to have new items added to it') def add_from_command_for_a_presentation_test(self): """ diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index 34872bb39..88d4b848f 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -39,7 +39,8 @@ from PyQt4 import QtGui from openlp.core.lib import Registry from openlp.core.common import Settings from openlp.plugins.remotes.lib.httpserver import HttpRouter -from mock import MagicMock, patch, mock_open +from tests.functional import MagicMock, patch +from mock import mock_open from urllib.parse import urlparse __default_settings__ = { @@ -53,6 +54,7 @@ __default_settings__ = { 'remotes/ip address': '0.0.0.0' } +TEST_PATH = os.path.abspath(os.path.dirname(__file__)) class TestRouter(TestCase): """ @@ -115,21 +117,65 @@ class TestRouter(TestCase): assert function['secure'] == False, \ 'The mocked function should not require any security.' - def get_appropriate_content_type_test(self): + def get_content_type_test(self): """ Test the get_content_type logic """ + # GIVEN: a set of files and their corresponding types headers = [ ['test.html', 'text/html'], ['test.css', 'text/css'], ['test.js', 'application/javascript'], ['test.jpg', 'image/jpeg'], ['test.gif', 'image/gif'], ['test.ico', 'image/x-icon'], ['test.png', 'image/png'], ['test.whatever', 'text/plain'], ['test', 'text/plain'], ['', 'text/plain'], - ['/test/test.html', 'text/html'], - ['c:\\test\\test.html', 'text/html']] + [os.path.join(TEST_PATH,'test.html'), 'text/html']] + # WHEN: calling each file type for header in headers: ext, content_type = self.router.get_content_type(header[0]) + # THEN: all types should match self.assertEqual(content_type, header[1], 'Mismatch of content type') + def serve_file_without_params_test(self): + """ + Test the serve_file method without params + """ + # GIVEN: mocked environment + self.router.send_response = MagicMock() + self.router.send_header = MagicMock() + self.router.end_headers = MagicMock() + self.router.wfile = MagicMock() + self.router.html_dir = os.path.normpath('test/dir') + self.router.template_vars = MagicMock() + # WHEN: call serve_file with no file_name + self.router.serve_file() + # THEN: it should return a 404 + self.router.send_response.assert_called_once_with(404) + self.router.send_header.assert_called_once_with('Content-type','text/html') + self.assertEqual(self.router.end_headers.call_count, 1, + 'end_headers called once') + + def serve_file_with_valid_params_test(self): + """ + Test the serve_file method with an existing file + """ + # GIVEN: mocked environment + self.router.send_response = MagicMock() + self.router.send_header = MagicMock() + self.router.end_headers = MagicMock() + self.router.wfile = MagicMock() + self.router.html_dir = os.path.normpath('test/dir') + self.router.template_vars = MagicMock() + with patch('openlp.core.lib.os.path.exists') as mocked_exists, \ + patch('builtins.open', mock_open(read_data='123')): + mocked_exists.return_value = True + # WHEN: call serve_file with an existing html file + self.router.serve_file(os.path.normpath('test/dir/test.html')) + # THEN: it should return a 200 and the file + self.router.send_response.assert_called_once_with(200) + self.router.send_header.assert_called_once_with( + 'Content-type','text/html') + self.assertEqual(self.router.end_headers.call_count, 1, + 'end_headers called once') + def serve_thumbnail_without_params_test(self): """ Test the serve_thumbnail routine without params