forked from openlp/openlp
-- 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:
parent
3bbaff362d
commit
00fd7f01f7
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user