diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 2e514935f..cbd2caadc 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -28,6 +28,7 @@ Provides the generic functions for interfacing plugins with the Media Manager. """ import logging import os +import re from PyQt4 import QtCore, QtGui @@ -90,6 +91,7 @@ class MediaManagerItem(QtGui.QWidget): """ QtGui.QWidget.__init__(self) self.parent = parent + self.whitespace = re.compile(r'\W+', re.UNICODE) #TODO: plugin should not be the parent in future self.plugin = parent # plugin visible_title = self.plugin.getString(StringContent.VisibleName) diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index 7b8a15c21..774789fa0 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -65,6 +65,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): QtCore.SIGNAL(u'theme_update_list'), self.loadThemes) QtCore.QObject.connect(self.slideListView, QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged) + QtCore.QObject.connect(self.slideListView, + QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), + self.onEditButtonPressed) def loadThemes(self, themelist): self.themeComboBox.clear() diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index e05b56314..66b1c3675 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -30,13 +30,22 @@ from PyQt4 import QtCore, QtGui from sqlalchemy.sql import or_, func from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ - check_item_selected + check_item_selected, translate +from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings from openlp.plugins.custom.lib import CustomXMLParser from openlp.plugins.custom.lib.db import CustomSlide log = logging.getLogger(__name__) +class CustomSearch(object): + """ + An enumeration for custom search methods. + """ + Titles = 1 + Themes = 2 + + class CustomMediaItem(MediaManagerItem): """ This is the custom media manager item for Custom Slides. @@ -55,6 +64,41 @@ class CustomMediaItem(MediaManagerItem): self.manager = parent.manager def addEndHeaderBar(self): + 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) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'custom_edit'), self.onRemoteEdit) QtCore.QObject.connect(Receiver.get_receiver(), @@ -64,9 +108,22 @@ class CustomMediaItem(MediaManagerItem): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick) + def retranslateUi(self): + self.searchTextLabel.setText(u'%s:' % UiStrings().Search) + self.searchTextButton.setText(UiStrings().Search) + def initialise(self): + self.searchTextEdit.setSearchTypes([ + (CustomSearch.Titles, u':/songs/song_search_title.png', + translate('SongsPlugin.MediaItem', 'Titles')), + (CustomSearch.Themes, u':/slides/slide_theme.png', + UiStrings().Themes) + ]) self.loadList(self.manager.get_all_objects( CustomSlide, order_by_ref=CustomSlide.title)) + self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value( + u'%s/last search type' % self.settingsSection, + QtCore.QVariant(CustomSearch.Titles)).toInt()[0]) # 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. @@ -165,6 +222,48 @@ class CustomMediaItem(MediaManagerItem): service_item.raw_footer = raw_footer 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') + search_results = self.parent.manager.get_all_objects(CustomSlide, + CustomSlide.title.like(u'%' + self.whitespace.sub(u' ', + search_keywords) + u'%'), order_by_ref=CustomSlide.title) + self.loadList(search_results) + elif search_type == CustomSearch.Themes: + log.debug(u'Theme Search') + search_results = self.parent.manager.get_all_objects(CustomSlide, + CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ', + search_keywords) + u'%'), order_by_ref=CustomSlide.title) + self.loadList(search_results) + self.check_search_result() + + 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 till 2 characters + 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() + def search(self, string): search_results = self.manager.get_all_objects(CustomSlide, or_(func.lower(CustomSlide.title).like(u'%' + @@ -176,3 +275,4 @@ class CustomMediaItem(MediaManagerItem): for custom in search_results: results.append([custom.id, custom.title]) return results + diff --git a/openlp/plugins/songs/lib/foilpresenterimport.py b/openlp/plugins/songs/lib/foilpresenterimport.py index c5dfd5d96..8cd328808 100644 --- a/openlp/plugins/songs/lib/foilpresenterimport.py +++ b/openlp/plugins/songs/lib/foilpresenterimport.py @@ -422,7 +422,8 @@ class FoilPresenter(object): VerseType.Tags[VerseType.PreChorus]: 1 } for strophe in foilpresenterfolie.strophen.strophe: - text = self._child(strophe.text_) + text = self._child(strophe.text_) if hasattr(strophe, u'text_') \ + else u'' verse_name = self._child(strophe.key) children = strophe.getchildren() sortnr = False diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 59ee05b7a..5f961b2f2 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -26,7 +26,6 @@ import logging import locale -import re from PyQt4 import QtCore, QtGui from sqlalchemy.sql import or_ @@ -72,7 +71,6 @@ class SongMediaItem(MediaManagerItem): # which Song is required. self.remoteSong = -1 self.editItem = None - self.whitespace = re.compile(r'\W+', re.UNICODE) self.quickPreviewAllowed = True self.hasSearch = True @@ -194,7 +192,8 @@ class SongMediaItem(MediaManagerItem): elif search_type == SongSearch.Themes: log.debug(u'Theme Search') search_results = self.parent.manager.get_all_objects(Song, - Song.theme_name == search_keywords) + Song.theme_name.like(u'%' + self.whitespace.sub(u' ', + search_keywords) + u'%')) self.displayResultsSong(search_results) self.check_search_result() @@ -221,8 +220,7 @@ class SongMediaItem(MediaManagerItem): # Push edits to the service manager to update items if self.editItem and self.updateServiceOnEdit and \ not self.remoteTriggered: - item_id = _getIdOfItemToGenerate(self.editItem) - item = self.buildServiceItem(item_id) + item = self.buildServiceItem(self.editItem) self.parent.serviceManager.replaceServiceItem(item) self.onRemoteEditClear() self.onSearchTextButtonClick()