-- General code cleanup to better match the architecture

-- Added thumbnails to the remote display
-- Modify the service list to use the displaytitle
This commit is contained in:
Felipe Polo-Wood 2013-10-19 01:27:25 -04:00
parent 3bbaff362d
commit 00fd7f01f7
9 changed files with 105 additions and 76 deletions

View File

@ -107,6 +107,16 @@ class ItemCapabilities(object):
``CanAutoStartForLive``
The capability to ignore the do not play if display blank flag.
``HasDisplayTitle``
The item contains 'displaytitle' on every frame which should be
preferred over 'title' when displaying the item
``HasNotes``
The item contains 'notes'
``HasThumbnails``
The item has related thumbnails available
"""
CanPreview = 1
CanEdit = 2
@ -124,6 +134,9 @@ class ItemCapabilities(object):
CanWordSplit = 14
HasBackgroundAudio = 15
CanAutoStartForLive = 16
HasDisplayTitle = 17
HasNotes = 18
HasThumbnails = 19
class ServiceItem(object):
@ -303,7 +316,7 @@ class ServiceItem(object):
self._raw_frames.append({'title': title, 'raw_slide': raw_slide, 'verseTag': verse_tag})
self._new_item()
def add_from_command(self, path, file_name, image):
def add_from_command(self, path, file_name, image, displaytitle=None, notes=None):
"""
Add a slide from a command.
@ -317,27 +330,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})
self._new_item()
def add_from_presentation(self, path, file_name, image, displaytitle, notes):
"""
Add a slide from a presentation.
``path``
The path of the presentation
``file_name``
The filename of the presentation
``image``
Full path (including file name) to the thumbnail
``displaytitle``
The title to display on the list and remote
"""
self.service_item_type = ServiceItemType.Command
self._raw_frames.append({'title': file_name, 'image': image, 'path': path, 'displaytitle': displaytitle, 'notes': notes})
self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
'displaytitle': displaytitle, 'notes': notes})
self._new_item()
def get_service_repr(self, lite_save):
@ -382,11 +376,8 @@ class ServiceItem(object):
service_data = [slide['title'] for slide in self._raw_frames]
elif self.service_item_type == ServiceItemType.Command:
for slide in self._raw_frames:
#if len(slide['displaytitle'])>0:
service_data.append({'title': slide['title'], 'image': slide['image'], 'path': slide['path'],
'displaytitle': slide['displaytitle'], 'notes': slide['notes']})
#else:
# service_data.append({'title': slide['title'], 'image': slide['image'], 'path': slide['path']})
return {'header': service_header, 'data': service_data}
def set_from_service(self, serviceitem, path=None):
@ -458,10 +449,8 @@ class ServiceItem(object):
self.title = text_image['title']
if path:
self.has_original_files = False
if serviceitem['serviceitem']['header']['plugin']=='presentations':
self.add_from_presentation(path, text_image['title'], text_image['image'], text_image['displaytitle'], text_image['notes'])
else:
self.add_from_command(path, text_image['title'], text_image['image'])
self.add_from_command(path, text_image['title'], text_image['image'],
text_image['displaytitle'], text_image['notes'])
else:
self.add_from_command(text_image['path'], text_image['title'], text_image['image'])
self._new_item()

View File

@ -1185,7 +1185,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
# Add the children to their parent treewidgetitem.
for count, frame in enumerate(serviceitem.get_frames()):
child = QtGui.QTreeWidgetItem(treewidgetitem)
text = frame['title'].replace('\n', ' ')
# prefer to use a displaytitle
if serviceitem.is_capable(ItemCapabilities.HasDisplayTitle):
text = frame['displaytitle'].replace('\n',' ')
# oops, it is missing, let's make one up
if len(text.strip()) == 0:
text = '[slide ' + str(count+1) + ']'
else:
text = frame['title'].replace('\n', ' ')
child.setText(0, text[:40])
child.setData(0, QtCore.Qt.UserRole, count)
if service_item == item_count:

View File

@ -466,6 +466,7 @@ class ImpressDocument(PresentationDocument):
shape = page.getByIndex(index)
shapeType = shape.getShapetype()
if shape.supportsService("com.sun.star.drawing.Text"):
# if they requested title, make sure it is the title
if text_type!=TextType.Title or shapeType == "com.sun.star.presentation.TitleTextShape":
text += shape.getString() + '\n'
return text
@ -492,8 +493,3 @@ class ImpressDocument(PresentationDocument):
fo.writelines(titles)
return
def get_titles_and_notes(self):
"""
let the super class handle it
"""
return super().get_titles_and_notes()

View File

@ -250,6 +250,7 @@ class PresentationMediaItem(MediaManagerItem):
return False
service_item.processor = self.display_type_combo_box.currentText()
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
service_item.add_capability(ItemCapabilities.HasThumbnails)
if not self.display_type_combo_box.currentText():
return False
for bitem in items:
@ -264,6 +265,10 @@ class PresentationMediaItem(MediaManagerItem):
controller = self.controllers[service_item.processor]
doc = controller.add_document(filename)
titles, notes = doc.get_titles_and_notes()
if len(titles) > 0:
service_item.add_capability(ItemCapabilities.HasDisplayTitle)
if len(notes) > 0:
service_item.add_capability(ItemCapabilities.HasNotes)
if doc.get_thumbnail_path(1, True) is None:
doc.load_presentation()
i = 1
@ -276,7 +281,7 @@ class PresentationMediaItem(MediaManagerItem):
note = ''
if i <= len(notes):
note = notes[i-1]
service_item.add_from_presentation(path, name, img, title, note)
service_item.add_from_command(path, name, img, title, note)
i += 1
img = doc.get_thumbnail_path(i, True)
doc.close_presentation()

View File

@ -344,12 +344,6 @@ class PowerpointDocument(PresentationDocument):
fo.writelines(titles)
return
def get_titles_and_notes(self):
"""
let the super class handle it
"""
return super().get_titles_and_notes()
def _get_text_from_shapes(shapes):
"""
Returns any text extracted from the shapes on a presentation slide.

View File

@ -179,12 +179,14 @@ class PptviewDocument(PresentationDocument):
index = -1
listToAdd = None
# check if it is a slide
match = re.search("slides/slide(.+)\.xml", zip_info.filename)
if match:
index = int(match.group(1))-1
nodeType = 'ctrTitle'
listToAdd = titles
# or a note
match = re.search("notesSlides/notesSlide(.+)\.xml", zip_info.filename)
if match:
index = int(match.group(1))-1
@ -197,7 +199,9 @@ class PptviewDocument(PresentationDocument):
tree = ElementTree.parse(zipped_file)
text = ''
nodes = tree.getroot().findall(".//p:ph[@type='" + nodeType + "']../../..//p:txBody//a:t", namespaces=namespaces)
nodes = tree.getroot().findall(".//p:ph[@type='" + nodeType + "']../../..//p:txBody//a:t",
namespaces=namespaces)
# if we found any content
if nodes and len(nodes)>0:
for node in nodes:
if len(text) > 0:
@ -205,7 +209,7 @@ class PptviewDocument(PresentationDocument):
text += node.text
print( 'slide file: ' + zip_info.filename + ' ' + text )
# let's remove the nl from the titles and just add one at the end
# let's remove the \n from the titles and just add one at the end
if nodeType == 'ctrTitle':
text = text.replace('\n',' ').replace('\x0b', ' ') + '\n'
listToAdd[index] = text
@ -319,9 +323,3 @@ class PptviewDocument(PresentationDocument):
Triggers the previous slide on the running presentation.
"""
self.controller.process.PrevStep(self.ppt_id)
def get_titles_and_notes(self):
"""
let the super class handle it
"""
return super().get_titles_and_notes()

View File

@ -209,7 +209,8 @@ class PPTViewer(QtGui.QWidget):
tree = ElementTree.parse(zipped_file)
text = ''
nodes = tree.getroot().findall(".//p:ph[@type='" + nodeType + "']../../..//p:txBody//a:t", namespaces=namespaces)
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:

View File

@ -87,13 +87,21 @@ window.OpenLP = {
var ul = $("#slide-controller > div[data-role=content] > ul[data-role=listview]");
ul.html("");
for (idx in data.results.slides) {
var text = data.results.slides[idx]["tag"];
var slide = data.results.slides[idx];
var text = slide["tag"];
if (text != "") text = text + ": ";
text = text + data.results.slides[idx]["text"];
if (slide["title"])
text += slide["title"]
else
text += slide["text"];
if (slide["notes"])
text += ("<div style='font-size:smaller;font-weight:normal'>" + slide["notes"] + "</div>");
text = text.replace(/\n/g, '<br />');
if (slide["img"])
text += "<img src='" + slide["img"] + "'>";
var li = $("<li data-icon=\"false\">").append(
$("<a href=\"#\">").attr("value", parseInt(idx, 10)).html(text));
if (data.results.slides[idx]["selected"]) {
if (slide["selected"]) {
li.attr("data-theme", "e");
}
li.children("a").click(OpenLP.setSlide);

View File

@ -125,7 +125,7 @@ from urllib.parse import urlparse, parse_qs
from mako.template import Template
from PyQt4 import QtCore
from openlp.core.lib import Registry, Settings, PluginStatus, StringContent, image_to_byte
from openlp.core.lib import Registry, Settings, PluginStatus, StringContent, image_to_byte, resize_image, ItemCapabilities
from openlp.core.utils import AppLocation, translate
log = logging.getLogger(__name__)
@ -151,6 +151,7 @@ class HttpRouter(object):
('^/(stage)$', {'function': self.serve_file, 'secure': False}),
('^/(main)$', {'function': self.serve_file, 'secure': False}),
(r'^/files/(.*)$', {'function': self.serve_file, 'secure': False}),
(r'^/(.*)/thumbnails/(.*)$', {'function': self.serve_thumbnail, 'secure': False}),
(r'^/api/poll$', {'function': self.poll, 'secure': False}),
(r'^/main/poll$', {'function': self.main_poll, 'secure': False}),
(r'^/main/image$', {'function': self.main_image, 'secure': False}),
@ -347,26 +348,10 @@ class HttpRouter(object):
path = os.path.normpath(os.path.join(self.html_dir, file_name))
if not path.startswith(self.html_dir):
return self.do_not_found()
ext = os.path.splitext(file_name)[1]
html = None
if ext == '.html':
self.send_header('Content-type', 'text/html')
if self.send_appropriate_header(file_name) == '.html':
variables = self.template_vars
html = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables)
elif ext == '.css':
self.send_header('Content-type', 'text/css')
elif ext == '.js':
self.send_header('Content-type', 'application/javascript')
elif ext == '.jpg':
self.send_header('Content-type', 'image/jpeg')
elif ext == '.gif':
self.send_header('Content-type', 'image/gif')
elif ext == '.ico':
self.send_header('Content-type', 'image/x-icon')
elif ext == '.png':
self.send_header('Content-type', 'image/png')
else:
self.send_header('Content-type', 'text/plain')
file_handle = None
try:
if html:
@ -383,6 +368,44 @@ class HttpRouter(object):
file_handle.close()
return content
def send_appropriate_header(self, file_name):
ext = os.path.splitext(file_name)[1]
if ext == '.html':
self.send_header('Content-type', 'text/html')
elif ext == '.css':
self.send_header('Content-type', 'text/css')
elif ext == '.js':
self.send_header('Content-type', 'application/javascript')
elif ext == '.jpg':
self.send_header('Content-type', 'image/jpeg')
elif ext == '.gif':
self.send_header('Content-type', 'image/gif')
elif ext == '.ico':
self.send_header('Content-type', 'image/x-icon')
elif ext == '.png':
self.send_header('Content-type', 'image/png')
else:
self.send_header('Content-type', 'text/plain')
return ext
def serve_thumbnail(self, controller_name=None, file_name=None):
"""
Serve an image file. If not found return 404.
"""
log.debug('serve thumbnail %s/thumbnails/%s' % (controller_name, file_name))
content = ''
full_path = os.path.join(AppLocation.get_section_data_path(controller_name),
'thumbnails/' + file_name.replace('/','\\') )
full_path = urllib.parse.unquote(full_path)
if os.path.exists(full_path):
self.send_appropriate_header(full_path)
file_handle = open(full_path, 'rb')
content = file_handle.read()
else:
content = self.do_not_found()
return content
def poll(self):
"""
Poll OpenLP to determine the current slide number and item name.
@ -470,12 +493,20 @@ class HttpRouter(object):
item['html'] = str(frame['html'])
else:
item['tag'] = str(index + 1)
if current_item.name == 'presentations':
item['text'] = str(frame['displaytitle']) + '\n' + str(frame['notes'])
else:
item['text'] = str(frame['title'])
if current_item.is_capable(ItemCapabilities.HasDisplayTitle):
item['title'] = str(frame['displaytitle'])
if current_item.is_capable(ItemCapabilities.HasNotes):
item['notes'] = str(frame['notes'])
if current_item.is_capable(ItemCapabilities.HasThumbnails):
# if the file is under our app directory tree send the portion after the match
if frame['image'][0:len(AppLocation.get_data_path())] == AppLocation.get_data_path():
item['img'] = frame['image'][len(AppLocation.get_data_path()):]
#'data:image/png;base64,' + str(image_to_byte(resize_image(frame['image'],80,80)))
item['text'] = str(frame['title'])
item['html'] = str(frame['title'])
item['selected'] = (self.live_controller.selected_row == index)
if current_item.notes:
item['notes'] = item.get('notes','') + '\n' + current_item.notes
data.append(item)
json_data = {'results': {'slides': data}}
if current_item: