openlp/openlp/plugins/custom/lib/mediaitem.py

306 lines
14 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2010-12-26 11:04:47 +00:00
# Copyright (c) 2008-2011 Raoul Snyman #
2011-05-26 16:25:54 +00:00
# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
2011-05-26 17:11:22 +00:00
# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
2011-06-12 16:02:52 +00:00
# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
2011-06-12 15:41:01 +00:00
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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
2011-05-20 15:14:10 +00:00
import locale
from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_, func
2011-02-10 18:38:03 +00:00
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
2011-05-15 19:18:50 +00:00
check_item_selected, translate
2011-05-15 19:07:40 +00:00
from openlp.core.lib.searchedit import SearchEdit
2011-02-13 14:21:12 +00:00
from openlp.core.lib.ui import UiStrings
from openlp.plugins.custom.forms import EditCustomForm
2010-07-03 01:33:40 +00:00
from openlp.plugins.custom.lib import CustomXMLParser
2010-06-15 02:08:22 +00:00
from openlp.plugins.custom.lib.db import CustomSlide
2010-02-27 15:31:23 +00:00
log = logging.getLogger(__name__)
2011-05-15 19:07:40 +00:00
class CustomSearch(object):
"""
2011-05-18 14:34:35 +00:00
An enumeration for custom search methods.
2011-05-15 19:07:40 +00:00
"""
Titles = 1
Themes = 2
class CustomMediaItem(MediaManagerItem):
"""
This is the custom media manager item for Custom Slides.
"""
log.info(u'Custom Media Item loaded')
2010-09-15 17:55:27 +00:00
def __init__(self, parent, plugin, icon):
2009-09-11 04:54:22 +00:00
self.IconPath = u'custom/custom'
2011-05-28 09:53:37 +00:00
MediaManagerItem.__init__(self, parent, plugin, icon)
self.edit_custom_form = EditCustomForm(self, self.plugin.formparent,
self.plugin.manager)
2010-04-06 19:16:14 +00:00
self.singleServiceItem = False
self.quickPreviewAllowed = True
self.hasSearch = True
# Holds information about whether the edit is remotly triggered and
# which Custom is required.
self.remoteCustom = -1
2011-05-28 09:53:37 +00:00
self.manager = plugin.manager
2009-10-29 13:44:33 +00:00
def addEndHeaderBar(self):
2011-05-15 19:07:40 +00:00
self.addToolbarSeparator()
self.searchWidget = QtGui.QWidget(self)
self.searchWidget.setObjectName(u'searchWidget')
self.searchLayout = QtGui.QVBoxLayout(self.searchWidget)
self.searchLayout.setObjectName(u'searchLayout')
self.searchTextLayout = QtGui.QFormLayout()
self.searchTextLayout.setObjectName(u'searchTextLayout')
self.searchTextLabel = QtGui.QLabel(self.searchWidget)
self.searchTextLabel.setObjectName(u'searchTextLabel')
self.searchTextEdit = SearchEdit(self.searchWidget)
self.searchTextEdit.setObjectName(u'searchTextEdit')
self.searchTextLabel.setBuddy(self.searchTextEdit)
self.searchTextLayout.addRow(self.searchTextLabel, self.searchTextEdit)
self.searchLayout.addLayout(self.searchTextLayout)
self.searchButtonLayout = QtGui.QHBoxLayout()
self.searchButtonLayout.setObjectName(u'searchButtonLayout')
self.searchButtonLayout.addStretch()
self.searchTextButton = QtGui.QPushButton(self.searchWidget)
self.searchTextButton.setObjectName(u'searchTextButton')
self.searchButtonLayout.addWidget(self.searchTextButton)
self.searchLayout.addLayout(self.searchButtonLayout)
self.pageLayout.addWidget(self.searchWidget)
# Signals and slots
QtCore.QObject.connect(self.searchTextEdit,
QtCore.SIGNAL(u'returnPressed()'), self.onSearchTextButtonClick)
QtCore.QObject.connect(self.searchTextButton,
QtCore.SIGNAL(u'pressed()'), self.onSearchTextButtonClick)
QtCore.QObject.connect(self.searchTextEdit,
QtCore.SIGNAL(u'textChanged(const QString&)'),
self.onSearchTextEditChanged)
QtCore.QObject.connect(self.searchTextEdit,
QtCore.SIGNAL(u'cleared()'), self.onClearTextButtonClick)
QtCore.QObject.connect(self.searchTextEdit,
QtCore.SIGNAL(u'searchTypeChanged(int)'),
self.onSearchTextButtonClick)
2009-10-29 13:44:33 +00:00
QtCore.QObject.connect(Receiver.get_receiver(),
2010-04-16 07:31:01 +00:00
QtCore.SIGNAL(u'custom_edit'), self.onRemoteEdit)
2009-10-29 13:44:33 +00:00
QtCore.QObject.connect(Receiver.get_receiver(),
2011-02-16 03:28:06 +00:00
QtCore.SIGNAL(u'custom_edit_clear'), self.onRemoteEditClear)
2009-10-29 13:44:33 +00:00
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'custom_load_list'), self.loadList)
QtCore.QObject.connect(Receiver.get_receiver(),
2010-04-16 07:31:01 +00:00
QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick)
2011-05-15 19:07:40 +00:00
def retranslateUi(self):
self.searchTextLabel.setText(u'%s:' % UiStrings().Search)
self.searchTextButton.setText(UiStrings().Search)
def initialise(self):
2011-05-15 19:07:40 +00:00
self.searchTextEdit.setSearchTypes([
(CustomSearch.Titles, u':/songs/song_search_title.png',
translate('SongsPlugin.MediaItem', 'Titles')),
(CustomSearch.Themes, u':/slides/slide_theme.png',
UiStrings().Themes)
])
2011-02-04 18:42:37 +00:00
self.loadList(self.manager.get_all_objects(
2010-07-18 23:37:24 +00:00
CustomSlide, order_by_ref=CustomSlide.title))
2011-05-15 19:07:40 +00:00
self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value(
u'%s/last search type' % self.settingsSection,
2011-05-15 19:18:50 +00:00
QtCore.QVariant(CustomSearch.Titles)).toInt()[0])
2011-05-20 15:18:57 +00:00
def loadList(self, custom_slides):
# Sort out what custom we want to select after loading the list.
self.save_auto_select_id()
2010-07-07 16:03:30 +00:00
self.listView.clear()
2011-05-20 15:14:10 +00:00
# Sort the customs by its title considering language specific
2011-05-24 05:23:28 +00:00
# characters. lower() is needed for windows!
2011-05-20 17:06:38 +00:00
custom_slides.sort(
2011-05-23 10:34:42 +00:00
cmp=locale.strcoll, key=lambda custom: custom.title.lower())
2011-05-20 15:18:57 +00:00
for custom_slide in custom_slides:
custom_name = QtGui.QListWidgetItem(custom_slide.title)
2009-09-21 17:56:36 +00:00
custom_name.setData(
2011-05-20 15:18:57 +00:00
QtCore.Qt.UserRole, QtCore.QVariant(custom_slide.id))
2010-07-07 16:03:30 +00:00
self.listView.addItem(custom_name)
# Auto-select the custom.
if custom_slide.id == self.auto_select_id:
self.listView.setCurrentItem(custom_name)
self.auto_select_id = -1
# Called to redisplay the custom list screen edith from a search
# or from the exit of the Custom edit dialog. If remote editing is
# active trigger it and clean up so it will not update again.
if self.remoteTriggered == u'L':
self.onAddClick()
if self.remoteTriggered == u'P':
self.onPreviewClick()
self.onRemoteEditClear()
2009-09-11 04:54:22 +00:00
def onNewClick(self):
self.edit_custom_form.loadCustom(0)
self.edit_custom_form.exec_()
self.onClearTextButtonClick()
self.onSelectionChange()
2009-10-29 13:44:33 +00:00
def onRemoteEditClear(self):
self.remoteTriggered = None
self.remoteCustom = -1
def onRemoteEdit(self, message):
"""
Called by ServiceManager or SlideController by event passing
the custom Id in the payload along with an indicator to say which
type of display is required.
"""
remote_type, custom_id = message.split(u':')
custom_id = int(custom_id)
valid = self.manager.get_object(CustomSlide, custom_id)
2009-11-03 19:01:53 +00:00
if valid:
self.remoteCustom = custom_id
self.remoteTriggered = remote_type
self.edit_custom_form.loadCustom(custom_id, (remote_type == u'P'))
self.edit_custom_form.exec_()
self.auto_select_id = -1
self.onSearchTextButtonClick()
2009-10-29 13:44:33 +00:00
2009-09-11 04:54:22 +00:00
def onEditClick(self):
"""
Edit a custom item
"""
if check_item_selected(self.listView, UiStrings().SelectEdit):
2010-07-07 16:03:30 +00:00
item = self.listView.currentItem()
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.edit_custom_form.loadCustom(item_id, False)
self.edit_custom_form.exec_()
self.auto_select_id = -1
self.onSearchTextButtonClick()
2009-09-11 04:54:22 +00:00
def onDeleteClick(self):
"""
Remove a custom item from the list and database
"""
if check_item_selected(self.listView, UiStrings().SelectDelete):
2011-06-08 01:37:07 +00:00
items = self.listView.selectedIndexes()
2011-06-28 04:52:46 +00:00
if QtGui.QMessageBox.question(self,
UiStrings().ConfirmDelete,
2011-06-28 04:52:46 +00:00
translate('CustomPlugin.MediaItem',
'Are you sure you want to delete the %n selected custom'
' slides(s)?', '',
2011-06-28 04:52:46 +00:00
QtCore.QCoreApplication.CodecForTr, len(items)),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No),
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
2011-06-28 04:52:46 +00:00
return
2010-07-07 16:03:30 +00:00
row_list = [item.row() for item in self.listView.selectedIndexes()]
row_list.sort(reverse=True)
id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0]
2010-07-07 16:03:30 +00:00
for item in self.listView.selectedIndexes()]
for id in id_list:
2011-05-28 09:53:37 +00:00
self.plugin.manager.delete_object(CustomSlide, id)
2011-08-25 19:52:07 +00:00
self.onSearchTextButtonClick()
def onFocus(self):
self.searchTextEdit.setFocus()
def generateSlideData(self, service_item, item=None, xmlVersion=False):
2009-05-02 11:16:08 +00:00
raw_footer = []
slide = None
theme = None
2011-02-01 00:33:50 +00:00
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
2010-04-03 07:10:31 +00:00
service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview)
2010-04-08 16:00:04 +00:00
service_item.add_capability(ItemCapabilities.AllowsLoop)
2011-03-28 17:04:31 +00:00
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
2011-05-28 09:53:37 +00:00
customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
title = customSlide.title
credit = customSlide.credits
service_item.edit_id = item_id
theme = customSlide.theme_name
2010-03-09 19:43:11 +00:00
if theme:
service_item.theme = theme
2010-07-03 01:33:40 +00:00
customXML = CustomXMLParser(customSlide.text)
verseList = customXML.get_verses()
raw_slides = [verse[1] for verse in verseList]
service_item.title = title
for slide in raw_slides:
service_item.add_from_text(slide[:30], slide)
if QtCore.QSettings().value(self.settingsSection + u'/display footer',
2010-04-28 14:17:42 +00:00
QtCore.QVariant(True)).toBool() or credit:
2010-03-09 19:43:11 +00:00
raw_footer.append(title + u' ' + credit)
else:
raw_footer.append(u'')
service_item.raw_footer = raw_footer
2011-05-15 19:07:40 +00:00
return True
def onSearchTextButtonClick(self):
# Save the current search type to the configuration.
QtCore.QSettings().setValue(u'%s/last search type' %
self.settingsSection,
QtCore.QVariant(self.searchTextEdit.currentSearchType()))
# Reload the list considering the new search type.
search_keywords = unicode(self.searchTextEdit.displayText())
search_results = []
search_type = self.searchTextEdit.currentSearchType()
if search_type == CustomSearch.Titles:
log.debug(u'Titles Search')
2011-05-28 09:53:37 +00:00
search_results = self.plugin.manager.get_all_objects(CustomSlide,
2011-05-15 19:07:40 +00:00
CustomSlide.title.like(u'%' + self.whitespace.sub(u' ',
2011-05-19 04:48:10 +00:00
search_keywords) + u'%'), order_by_ref=CustomSlide.title)
2011-05-15 19:07:40 +00:00
self.loadList(search_results)
elif search_type == CustomSearch.Themes:
log.debug(u'Theme Search')
2011-05-28 09:53:37 +00:00
search_results = self.plugin.manager.get_all_objects(CustomSlide,
2011-05-15 19:07:40 +00:00
CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ',
2011-05-19 04:48:10 +00:00
search_keywords) + u'%'), order_by_ref=CustomSlide.title)
2011-05-15 19:07:40 +00:00
self.loadList(search_results)
2011-05-15 19:18:50 +00:00
self.check_search_result()
2011-05-15 19:07:40 +00:00
def onSearchTextEditChanged(self, text):
"""
If search as type enabled invoke the search on each key press.
If the Title is being searched do not start until 2 characters
2011-05-15 19:07:40 +00:00
have been entered.
"""
search_length = 2
if len(text) > search_length:
self.onSearchTextButtonClick()
elif len(text) == 0:
self.onClearTextButtonClick()
def onClearTextButtonClick(self):
"""
Clear the search text.
"""
self.searchTextEdit.clear()
self.onSearchTextButtonClick()
2011-05-18 14:27:29 +00:00
def search(self, string):
search_results = self.manager.get_all_objects(CustomSlide,
or_(func.lower(CustomSlide.title).like(u'%' +
string.lower() + u'%'),
func.lower(CustomSlide.text).like(u'%' +
string.lower() + u'%')),
order_by_ref=CustomSlide.title)
return [[custom.id, custom.title] for custom in search_results]
2011-05-18 14:27:29 +00:00