diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 1b001dfa7..27a34d54d 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -223,28 +223,6 @@ def resize_image(image, width, height, background=QtCore.Qt.black): painter.drawImage((width - realw) / 2, (height - realh) / 2, preview) return new_image -def check_search_result(treeWidget, search_results): - """ - Checks if the given ``search_results`` is empty and adds a - "No Search Results" item to the given ``treeWidget``. - - ``treeWidget`` - The ``QTreeWidget`` where the "No Search Results" item should be added - to, if the ``search_results`` is empty. - - ``search_results`` - This can either be a list or a dict. - """ - if search_results or treeWidget.count(): - return - message = translate('OpenLP.MediaManagerItem', 'No Search Results') - item = QtGui.QListWidgetItem(message) - item.setFlags(QtCore.Qt.NoItemFlags) - font = QtGui.QFont() - font.setItalic(True) - item.setFont(font) - treeWidget.addItem(item) - def check_item_selected(list_widget, message): """ Check if a list item is selected so an action may be performed on it diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 99a42e3cf..2e514935f 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -102,6 +102,7 @@ class MediaManagerItem(QtGui.QWidget): self.remoteTriggered = None self.singleServiceItem = True self.quickPreviewAllowed = False + self.hasSearch = False self.pageLayout = QtGui.QVBoxLayout(self) self.pageLayout.setSpacing(0) self.pageLayout.setMargin(0) @@ -244,7 +245,6 @@ class MediaManagerItem(QtGui.QWidget): """ # Add the List widget self.listView = ListWidgetWithDnD(self, self.plugin.name) - self.listView.setUniformItemSizes(True) self.listView.setSpacing(1) self.listView.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) @@ -475,11 +475,23 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', 'You must select one or more items to send live.')) else: - log.debug(u'%s Live requested', self.plugin.name) - serviceItem = self.buildServiceItem() - if serviceItem: + self.goLive() + + def goLive(self, item_id=None): + log.debug(u'%s Live requested', self.plugin.name) + item = None + if item_id: + item = self.createItemFromId(item_id) + serviceItem = self.buildServiceItem(item) + if serviceItem: + if not item_id: serviceItem.from_plugin = True - self.parent.liveController.addServiceItem(serviceItem) + self.parent.liveController.addServiceItem(serviceItem) + + def createItemFromId(self, item_id): + item = QtGui.QListWidgetItem() + item.setData(QtCore.Qt.UserRole, QtCore.QVariant(item_id)) + return item def onAddClick(self): """ @@ -552,6 +564,20 @@ class MediaManagerItem(QtGui.QWidget): """ pass + def check_search_result(self): + """ + Checks if the listView is empty and adds a "No Search Results" item. + """ + if self.listView.count(): + return + message = translate('OpenLP.MediaManagerItem', 'No Search Results') + item = QtGui.QListWidgetItem(message) + item.setFlags(QtCore.Qt.NoItemFlags) + font = QtGui.QFont() + font.setItalic(True) + item.setFont(font) + self.listView.addItem(item) + def _getIdOfItemToGenerate(self, item, remoteItem): """ Utility method to check items being submitted for slide generation. @@ -573,3 +599,10 @@ class MediaManagerItem(QtGui.QWidget): else: item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] return item_id + + def search(self, string): + """ + Performs a plugin specific search for items containing ``string`` + """ + raise NotImplementedError( + u'Plugin.search needs to be defined by the plugin') diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 0fddc75c4..682352aa5 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -211,3 +211,12 @@ class PluginManager(object): if plugin.isActive(): plugin.finalise() log.info(u'Finalisation Complete for %s ' % plugin.name) + + def get_plugin_by_name(self, name): + """ + Return the plugin which has a name with value ``name`` + """ + for plugin in self.plugins: + if plugin.name == name: + return plugin + return None diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index f3b0a43fa..20d5c3d62 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -162,8 +162,10 @@ class Renderer(object): self.theme_data = self.theme_manager.getThemeData(theme) self._calculate_default(self.screens.current[u'size']) self._build_text_rectangle(self.theme_data) - self.image_manager.add_image(self.theme_data.theme_name, - self.theme_data.background_filename) + # if No file do not update cache + if self.theme_data.background_filename: + self.image_manager.add_image(self.theme_data.theme_name, + self.theme_data.background_filename) return self._rect, self._rect_footer def generate_preview(self, theme_data, force_page=False): @@ -298,7 +300,7 @@ class Renderer(object): # Adjust width and height to account for shadow. outline done in css self.page_shell = u'' \ + u'#main {position:absolute; top:0px; %s %s}' \ u'
' % \ (build_lyrics_format_css(self.theme_data, self.page_width, self.page_height), build_lyrics_outline_css(self.theme_data)) diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index e1396d984..53fd37ed9 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -50,7 +50,6 @@ class SettingsTab(QtGui.QWidget): self.setupUi() self.retranslateUi() self.initialise() - self.preLoad() self.load() def setupUi(self): @@ -86,12 +85,6 @@ class SettingsTab(QtGui.QWidget): left_width = max(left_width, self.leftColumn.minimumSizeHint().width()) self.leftColumn.setFixedWidth(left_width) - def preLoad(self): - """ - Setup the tab's interface. - """ - pass - def retranslateUi(self): """ Setup the interface translation strings. @@ -118,9 +111,9 @@ class SettingsTab(QtGui.QWidget): def cancel(self): """ - Reset any settings + Reset any settings if cancel pressed """ - pass + self.load() def postSetUp(self, postUpdate=False): """ diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/displaytagform.py index b8169b9be..c439fc116 100644 --- a/openlp/core/ui/displaytagform.py +++ b/openlp/core/ui/displaytagform.py @@ -47,7 +47,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ QtGui.QDialog.__init__(self, parent) self.setupUi(self) - self.preLoad() + self._loadDisplayTags() QtCore.QObject.connect(self.tagTableWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected) QtCore.QObject.connect(self.defaultPushButton, @@ -66,12 +66,12 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): Load Display and set field state. """ # Create initial copy from master - self.preLoad() + self._loadDisplayTags() self._resetTable() self.selected = -1 return QtGui.QDialog.exec_(self) - def preLoad(self): + def _loadDisplayTags(self): """ Load the Tags from store so can be used in the system or used to update the display. If Cancel was selected this is needed to reset the diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index bd6a8e373..75cb8fa98 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -101,6 +101,7 @@ class GeneralTab(SettingsTab): self.timeoutLabel.setObjectName(u'timeoutLabel') self.timeoutSpinBox = QtGui.QSpinBox(self.settingsGroupBox) self.timeoutSpinBox.setObjectName(u'timeoutSpinBox') + self.timeoutSpinBox.setRange(1, 180) self.settingsLayout.addRow(self.timeoutLabel, self.timeoutSpinBox) self.leftLayout.addWidget(self.settingsGroupBox) self.leftLayout.addStretch() diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 048b434ba..c298f897f 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -199,8 +199,7 @@ class SlideController(QtGui.QWidget): 'Start/Stop continuous loop')) self.addAction(self.toogleLoop) self.delaySpinBox = QtGui.QSpinBox() - self.delaySpinBox.setMinimum(1) - self.delaySpinBox.setMaximum(180) + self.delaySpinBox.setRange(1, 180) self.toolbar.addToolbarWidget(u'Image SpinBox', self.delaySpinBox) self.delaySpinBox.setSuffix(UiStrings().Seconds) self.delaySpinBox.setToolTip(translate('OpenLP.SlideController', diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index ec63dc02f..55b00a56b 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -323,7 +323,7 @@ class BibleDB(QtCore.QObject, Manager): """ return self.get_all_objects(Book, order_by_ref=Book.id) - def get_verses(self, reference_list): + def get_verses(self, reference_list, show_error=True): """ This is probably the most used function. It retrieves the list of verses based on the user's query. @@ -360,11 +360,12 @@ class BibleDB(QtCore.QObject, Manager): verse_list.extend(verses) else: log.debug(u'OpenLP failed to find book %s', book) - critical_error_message_box( - translate('BiblesPlugin', 'No Book Found'), - translate('BiblesPlugin', 'No matching book ' - 'could be found in this Bible. Check that you have ' - 'spelled the name of the book correctly.')) + if show_error: + critical_error_message_box( + translate('BiblesPlugin', 'No Book Found'), + translate('BiblesPlugin', 'No matching book ' + 'could be found in this Bible. Check that you ' + 'have spelled the name of the book correctly.')) return verse_list def verse_search(self, text): @@ -401,7 +402,7 @@ class BibleDB(QtCore.QObject, Manager): """ log.debug(u'BibleDB.get_chapter_count("%s")', book) count = self.session.query(Verse.chapter).join(Book)\ - .filter(Book.name==book)\ + .filter(Book.name == book)\ .distinct().count() if not count: return 0 @@ -420,8 +421,8 @@ class BibleDB(QtCore.QObject, Manager): """ log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter) count = self.session.query(Verse).join(Book)\ - .filter(Book.name==book)\ - .filter(Verse.chapter==chapter)\ + .filter(Book.name == book)\ + .filter(Verse.chapter == chapter)\ .count() if not count: return 0 diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 6a6ef131a..d86b650d5 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -425,7 +425,7 @@ class HTTPBible(BibleDB): self.create_meta(u'proxy password', self.proxy_password) return True - def get_verses(self, reference_list): + def get_verses(self, reference_list, show_error=True): """ A reimplementation of the ``BibleDB.get_verses`` method, this one is specifically for web Bibles. It first checks to see if the particular @@ -453,11 +453,12 @@ class HTTPBible(BibleDB): if not db_book: book_details = HTTPBooks.get_book(book) if not book_details: - critical_error_message_box( - translate('BiblesPlugin', 'No Book Found'), - translate('BiblesPlugin', 'No matching ' - 'book could be found in this Bible. Check that you ' - 'have spelled the name of the book correctly.')) + if show_error: + critical_error_message_box( + translate('BiblesPlugin', 'No Book Found'), + translate('BiblesPlugin', 'No matching ' + 'book could be found in this Bible. Check that you ' + 'have spelled the name of the book correctly.')) return [] db_book = self.create_book(book_details[u'name'], book_details[u'abbreviation'], @@ -480,7 +481,7 @@ class HTTPBible(BibleDB): Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'cursor_normal') Receiver.send_message(u'openlp_process_events') - return BibleDB.get_verses(self, reference_list) + return BibleDB.get_verses(self, reference_list, show_error) def get_chapter(self, book, chapter): """ diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 67469e063..df31b2d0e 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -231,7 +231,7 @@ class BibleManager(object): bible, book, chapter) return self.db_cache[bible].get_verse_count(book, chapter) - def get_verses(self, bible, versetext): + def get_verses(self, bible, versetext, show_error=True): """ Parses a scripture reference, fetches the verses from the Bible specified, and returns a list of ``Verse`` objects. @@ -252,32 +252,34 @@ class BibleManager(object): """ log.debug(u'BibleManager.get_verses("%s", "%s")', bible, versetext) if not bible: - Receiver.send_message(u'openlp_information_message', { - u'title': translate('BiblesPlugin.BibleManager', - 'No Bibles Available'), - u'message': translate('BiblesPlugin.BibleManager', - 'There are no Bibles currently installed. Please use the ' - 'Import Wizard to install one or more Bibles.') - }) + if show_error: + Receiver.send_message(u'openlp_information_message', { + u'title': translate('BiblesPlugin.BibleManager', + 'No Bibles Available'), + u'message': translate('BiblesPlugin.BibleManager', + 'There are no Bibles currently installed. Please use the ' + 'Import Wizard to install one or more Bibles.') + }) return None reflist = parse_reference(versetext) if reflist: - return self.db_cache[bible].get_verses(reflist) + return self.db_cache[bible].get_verses(reflist, show_error) else: - Receiver.send_message(u'openlp_information_message', { - u'title': translate('BiblesPlugin.BibleManager', - 'Scripture Reference Error'), - u'message': translate('BiblesPlugin.BibleManager', - 'Your scripture reference is either not supported by OpenLP ' - 'or is invalid. Please make sure your reference conforms to ' - 'one of the following patterns:\n\n' - 'Book Chapter\n' - 'Book Chapter-Chapter\n' - 'Book Chapter:Verse-Verse\n' - 'Book Chapter:Verse-Verse,Verse-Verse\n' - 'Book Chapter:Verse-Verse,Chapter:Verse-Verse\n' - 'Book Chapter:Verse-Chapter:Verse') - }) + if show_error: + Receiver.send_message(u'openlp_information_message', { + u'title': translate('BiblesPlugin.BibleManager', + 'Scripture Reference Error'), + u'message': translate('BiblesPlugin.BibleManager', + 'Your scripture reference is either not supported by ' + 'OpenLP or is invalid. Please make sure your reference ' + 'conforms to one of the following patterns:\n\n' + 'Book Chapter\n' + 'Book Chapter-Chapter\n' + 'Book Chapter:Verse-Verse\n' + 'Book Chapter:Verse-Verse,Verse-Verse\n' + 'Book Chapter:Verse-Verse,Chapter:Verse-Verse\n' + 'Book Chapter:Verse-Chapter:Verse') + }) return None def verse_search(self, bible, second_bible, text): @@ -285,7 +287,7 @@ class BibleManager(object): Does a verse search for the given bible and text. ``bible`` - The bible to seach in (unicode). + The bible to search in (unicode). ``second_bible`` The second bible (unicode). We do not search in this bible. @@ -294,6 +296,15 @@ class BibleManager(object): The text to search for (unicode). """ log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text) + if not bible: + Receiver.send_message(u'openlp_information_message', { + u'title': translate('BiblesPlugin.BibleManager', + 'No Bibles Available'), + u'message': translate('BiblesPlugin.BibleManager', + 'There are no Bibles currently installed. Please use the ' + 'Import Wizard to install one or more Bibles.') + }) + return None # Check if the bible or second_bible is a web bible. webbible = self.db_cache[bible].get_object(BibleMeta, u'download source') diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 281f9bcc5..9a9e3f9ec 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -29,7 +29,7 @@ import logging from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ - translate, check_search_result + translate from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings, add_widget_completer, \ media_item_combo_box, critical_error_message_box, find_and_set_in_combo_box @@ -61,12 +61,46 @@ class BibleMediaItem(MediaManagerItem): # Place to store the search results for both bibles. self.settings = self.parent.settings_tab self.quickPreviewAllowed = True + self.hasSearch = True self.search_results = {} self.second_search_results = {} - check_search_result(self.listView, self.search_results) + self.check_search_result() QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles) + def __checkSecondBible(self, bible, second_bible): + """ + Check if the first item is a second bible item or not. + """ + bitem = self.listView.item(0) + if not bitem.flags() & QtCore.Qt.ItemIsSelectable: + # The item is the "No Search Results" item. + self.listView.clear() + self.displayResults(bible, second_bible) + return + else: + item_second_bible = self._decodeQtObject(bitem, 'second_bible') + if item_second_bible and second_bible or not item_second_bible and \ + not second_bible: + self.displayResults(bible, second_bible) + elif critical_error_message_box( + message=translate('BiblePlugin.MediaItem', + 'You cannot combine single and dual Bible verse search results. ' + 'Do you want to delete your search results and start a new ' + 'search?'), + parent=self, question=True) == QtGui.QMessageBox.Yes: + self.listView.clear() + self.displayResults(bible, second_bible) + + def _decodeQtObject(self, bitem, key): + reference = bitem.data(QtCore.Qt.UserRole) + if isinstance(reference, QtCore.QVariant): + reference = reference.toPyObject() + obj = reference[QtCore.QString(key)] + if isinstance(obj, QtCore.QVariant): + obj = obj.toPyObject() + return unicode(obj).strip() + def requiredIcons(self): MediaManagerItem.requiredIcons(self) self.hasImportIcon = True @@ -114,6 +148,12 @@ class BibleMediaItem(MediaManagerItem): secondComboBox = media_item_combo_box(tab, prefix + u'SecondComboBox') versionLabel.setBuddy(secondComboBox) layout.addWidget(secondComboBox, idx + 1, 1, 1, 2) + styleLabel = QtGui.QLabel(tab) + styleLabel.setObjectName(prefix + u'StyleLabel') + layout.addWidget(styleLabel, idx + 2, 0, QtCore.Qt.AlignRight) + styleComboBox = media_item_combo_box(tab, prefix + u'StyleComboBox') + styleComboBox.addItems([u'', u'', u'']) + layout.addWidget(styleComboBox, idx + 2, 1, 1, 2) searchButtonLayout = QtGui.QHBoxLayout() searchButtonLayout.setObjectName(prefix + u'SearchButtonLayout') searchButtonLayout.addStretch() @@ -125,7 +165,7 @@ class BibleMediaItem(MediaManagerItem): searchButton = QtGui.QPushButton(tab) searchButton.setObjectName(prefix + u'SearchButton') searchButtonLayout.addWidget(searchButton) - layout.addLayout(searchButtonLayout, idx + 2, 1, 1, 2) + layout.addLayout(searchButtonLayout, idx + 3, 1, 1, 2) self.pageLayout.addWidget(tab) tab.setVisible(False) QtCore.QObject.connect(lockButton, QtCore.SIGNAL(u'toggled(bool)'), @@ -134,6 +174,8 @@ class BibleMediaItem(MediaManagerItem): setattr(self, prefix + u'VersionComboBox', versionComboBox) setattr(self, prefix + u'SecondLabel', secondLabel) setattr(self, prefix + u'SecondComboBox', secondComboBox) + setattr(self, prefix + u'StyleLabel', styleLabel) + setattr(self, prefix + u'StyleComboBox', styleComboBox) setattr(self, prefix + u'LockButton', lockButton) setattr(self, prefix + u'SearchButtonLayout', searchButtonLayout) setattr(self, prefix + u'SearchButton', searchButton) @@ -154,14 +196,6 @@ class BibleMediaItem(MediaManagerItem): self.quickSearchEdit.setObjectName(u'quickSearchEdit') self.quickSearchLabel.setBuddy(self.quickSearchEdit) self.quickLayout.addWidget(self.quickSearchEdit, 0, 1, 1, 2) - self.quickLayoutLabel = QtGui.QLabel(self.quickTab) - self.quickLayoutLabel.setObjectName(u'quickClearLabel') - self.quickLayout.addWidget( - self.quickLayoutLabel, 1, 0, QtCore.Qt.AlignRight) - self.quickLayoutComboBox = media_item_combo_box(self.quickTab, - u'quickLayoutComboBox') - self.quickLayoutComboBox.addItems([u'', u'', u'']) - self.quickLayout.addWidget(self.quickLayoutComboBox, 1, 1, 1, 2) self.addSearchFields( u'quick', translate('BiblesPlugin.MediaItem', 'Quick')) self.quickTab.setVisible(True) @@ -218,8 +252,11 @@ class BibleMediaItem(MediaManagerItem): QtCore.QObject.connect(self.quickVersionComboBox, QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter) QtCore.QObject.connect( - self.quickLayoutComboBox, QtCore.SIGNAL(u'activated(int)'), - self.onLayoutStyleComboBoxChanged) + self.quickStyleComboBox, QtCore.SIGNAL(u'activated(int)'), + self.onQuickStyleComboBoxChanged) + QtCore.QObject.connect( + self.advancedStyleComboBox, QtCore.SIGNAL(u'activated(int)'), + self.onAdvancedStyleComboBoxChanged) # Buttons QtCore.QObject.connect(self.advancedSearchButton, QtCore.SIGNAL(u'pressed()'), self.onAdvancedSearchButton) @@ -247,21 +284,26 @@ class BibleMediaItem(MediaManagerItem): self.advancedSecondComboBox.setVisible(False) self.quickSecondLabel.setVisible(False) self.quickSecondComboBox.setVisible(False) - self.quickLayoutComboBox.setCurrentIndex(self.settings.layout_style) + self.quickStyleComboBox.setCurrentIndex(self.settings.layout_style) + self.advancedStyleComboBox.setCurrentIndex(self.settings.layout_style) def retranslateUi(self): log.debug(u'retranslateUi') + self.quickSearchLabel.setText( + translate('BiblesPlugin.MediaItem', 'Find:')) self.quickVersionLabel.setText(u'%s:' % UiStrings().Version) self.quickSecondLabel.setText( translate('BiblesPlugin.MediaItem', 'Second:')) - self.quickSearchLabel.setText( - translate('BiblesPlugin.MediaItem', 'Find:')) - self.quickSearchButton.setText(UiStrings().Search) + self.quickStyleLabel.setText(UiStrings().LayoutStyle) + self.quickStyleComboBox.setItemText(LayoutStyle.VersePerSlide, + UiStrings().VersePerSlide) + self.quickStyleComboBox.setItemText(LayoutStyle.VersePerLine, + UiStrings().VersePerLine) + self.quickStyleComboBox.setItemText(LayoutStyle.Continuous, + UiStrings().Continuous) self.quickLockButton.setToolTip(translate('BiblesPlugin.MediaItem', 'Toggle to keep or clear the previous results.')) - self.advancedVersionLabel.setText(u'%s:' % UiStrings().Version) - self.advancedSecondLabel.setText( - translate('BiblesPlugin.MediaItem', 'Second:')) + self.quickSearchButton.setText(UiStrings().Search) self.advancedBookLabel.setText( translate('BiblesPlugin.MediaItem', 'Book:')) self.advancedChapterLabel.setText( @@ -272,16 +314,19 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'From:')) self.advancedToLabel.setText( translate('BiblesPlugin.MediaItem', 'To:')) - self.advancedSearchButton.setText(UiStrings().Search) + self.advancedVersionLabel.setText(u'%s:' % UiStrings().Version) + self.advancedSecondLabel.setText( + translate('BiblesPlugin.MediaItem', 'Second:')) + self.advancedStyleLabel.setText(UiStrings().LayoutStyle) + self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerSlide, + UiStrings().VersePerSlide) + self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerLine, + UiStrings().VersePerLine) + self.advancedStyleComboBox.setItemText(LayoutStyle.Continuous, + UiStrings().Continuous) self.advancedLockButton.setToolTip(translate('BiblesPlugin.MediaItem', 'Toggle to keep or clear the previous results.')) - self.quickLayoutLabel.setText(UiStrings().LayoutStyle) - self.quickLayoutComboBox.setItemText(LayoutStyle.VersePerSlide, - UiStrings().VersePerSlide) - self.quickLayoutComboBox.setItemText(LayoutStyle.VersePerLine, - UiStrings().VersePerLine) - self.quickLayoutComboBox.setItemText(LayoutStyle.Continuous, - UiStrings().Continuous) + self.advancedSearchButton.setText(UiStrings().Search) def initialise(self): log.debug(u'bible manager initialise') @@ -303,28 +348,6 @@ class BibleMediaItem(MediaManagerItem): self.configUpdated() log.debug(u'bible manager initialise complete') - def onImportClick(self): - if not hasattr(self, u'import_wizard'): - self.import_wizard = BibleImportForm(self, self.parent.manager, - self.parent) - # If the import was not cancelled then reload. - if self.import_wizard.exec_(): - self.reloadBibles() - - def onSearchTabBarCurrentChanged(self, index): - if index == 0: - self.advancedTab.setVisible(False) - self.quickTab.setVisible(True) - else: - self.quickTab.setVisible(False) - self.advancedTab.setVisible(True) - - def onLockButtonToggled(self, checked): - if checked: - self.sender().setIcon(self.lockIcon) - else: - self.sender().setIcon(self.unlockIcon) - def loadBibles(self): log.debug(u'Loading Bibles') self.quickVersionComboBox.clear() @@ -422,6 +445,47 @@ class BibleMediaItem(MediaManagerItem): books.sort() add_widget_completer(books, self.quickSearchEdit) + def onImportClick(self): + if not hasattr(self, u'import_wizard'): + self.import_wizard = BibleImportForm(self, self.parent.manager, + self.parent) + # If the import was not cancelled then reload. + if self.import_wizard.exec_(): + self.reloadBibles() + + def onSearchTabBarCurrentChanged(self, index): + if index == 0: + self.advancedTab.setVisible(False) + self.quickTab.setVisible(True) + self.quickSearchEdit.setFocus() + else: + self.quickTab.setVisible(False) + self.advancedTab.setVisible(True) + + def onLockButtonToggled(self, checked): + if checked: + self.sender().setIcon(self.lockIcon) + else: + self.sender().setIcon(self.unlockIcon) + + def onQuickStyleComboBoxChanged(self): + self.settings.layout_style = self.quickStyleComboBox.currentIndex() + self.advancedStyleComboBox.setCurrentIndex(self.settings.layout_style) + self.settings.layoutStyleComboBox.setCurrentIndex( + self.settings.layout_style) + QtCore.QSettings().setValue( + self.settingsSection + u'/verse layout style', + QtCore.QVariant(self.settings.layout_style)) + + def onAdvancedStyleComboBoxChanged(self): + self.settings.layout_style = self.advancedStyleComboBox.currentIndex() + self.quickStyleComboBox.setCurrentIndex(self.settings.layout_style) + self.settings.layoutStyleComboBox.setCurrentIndex( + self.settings.layout_style) + QtCore.QSettings().setValue( + self.settingsSection + u'/verse layout style', + QtCore.QVariant(self.settings.layout_style)) + def onAdvancedVersionComboBox(self): QtCore.QSettings().setValue(self.settingsSection + u'/advanced bible', QtCore.QVariant(self.advancedVersionComboBox.currentText())) @@ -537,7 +601,7 @@ class BibleMediaItem(MediaManagerItem): elif self.search_results: self.displayResults(bible, second_bible) self.advancedSearchButton.setEnabled(True) - check_search_result(self.listView, self.search_results) + self.check_search_result() Receiver.send_message(u'cursor_normal') Receiver.send_message(u'openlp_process_events') @@ -578,35 +642,24 @@ class BibleMediaItem(MediaManagerItem): elif self.search_results: self.displayResults(bible, second_bible) self.quickSearchButton.setEnabled(True) - check_search_result(self.listView, self.search_results) + self.check_search_result() Receiver.send_message(u'cursor_normal') Receiver.send_message(u'openlp_process_events') - def __checkSecondBible(self, bible, second_bible): - """ - Check if the first item is a second bible item or not. - """ - bitem = self.listView.item(0) - if not bitem.flags() & QtCore.Qt.ItemIsSelectable: - # The item is the "No Search Results" item. - self.listView.clear() - self.displayResults(bible, second_bible) - return - else: - item_second_bible = self._decodeQtObject(bitem, 'second_bible') - if item_second_bible and second_bible or not item_second_bible and \ - not second_bible: - self.displayResults(bible, second_bible) - elif critical_error_message_box( - message=translate('BiblePlugin.MediaItem', - 'You cannot combine single and dual Bible verse search results. ' - 'Do you want to delete your search results and start a new ' - 'search?'), - parent=self, question=True) == QtGui.QMessageBox.Yes: - self.listView.clear() - self.displayResults(bible, second_bible) - def displayResults(self, bible, second_bible=u''): + """ + Displays the search results in the media manager. All data needed for + further action is saved for/in each row. + """ + items = self.buildDisplayResults(bible, second_bible, + self.search_results) + for bible_verse in items: + self.listView.addItem(bible_verse) + self.listView.selectAll() + self.search_results = {} + self.second_search_results = {} + + def buildDisplayResults(self, bible, second_bible, search_results): """ Displays the search results in the media manager. All data needed for further action is saved for/in each row. @@ -626,7 +679,8 @@ class BibleMediaItem(MediaManagerItem): second_bible, u'Copyright').value second_permissions = self.parent.manager.get_meta_data( second_bible, u'Permissions').value - for count, verse in enumerate(self.search_results): + items = [] + for count, verse in enumerate(search_results): data = { 'book': QtCore.QVariant(verse.book.name), 'chapter': QtCore.QVariant(verse.chapter), @@ -658,19 +712,8 @@ class BibleMediaItem(MediaManagerItem): verse.chapter, verse_separator, verse.verse, version) bible_verse = QtGui.QListWidgetItem(bible_text) bible_verse.setData(QtCore.Qt.UserRole, QtCore.QVariant(data)) - self.listView.addItem(bible_verse) - self.listView.selectAll() - self.search_results = {} - self.second_search_results = {} - - def _decodeQtObject(self, bitem, key): - reference = bitem.data(QtCore.Qt.UserRole) - if isinstance(reference, QtCore.QVariant): - reference = reference.toPyObject() - obj = reference[QtCore.QString(key)] - if isinstance(obj, QtCore.QVariant): - obj = obj.toPyObject() - return unicode(obj).strip() + items.append(bible_verse) + return items def generateSlideData(self, service_item, item=None, xmlVersion=False): """ @@ -678,7 +721,10 @@ class BibleMediaItem(MediaManagerItem): service item's title. """ log.debug(u'generating slide data') - items = self.listView.selectedIndexes() + if item: + items = item + else: + items = self.listView.selectedItems() if len(items) == 0: return False bible_text = u'' @@ -687,8 +733,7 @@ class BibleMediaItem(MediaManagerItem): raw_slides = [] raw_title = [] verses = VerseReferenceList() - for item in items: - bitem = self.listView.item(item.row()) + for bitem in items: book = self._decodeQtObject(bitem, 'book') chapter = int(self._decodeQtObject(bitem, 'chapter')) verse = int(self._decodeQtObject(bitem, 'verse')) @@ -722,11 +767,11 @@ class BibleMediaItem(MediaManagerItem): else: bible_text = u'%s %s %s\n' % (bible_text, verse_text, text) if not old_item: - start_item = item - elif self.checkTitle(item, old_item): + start_item = bitem + elif self.checkTitle(bitem, old_item): raw_title.append(self.formatTitle(start_item, old_item)) - start_item = item - old_item = item + start_item = bitem + old_item = bitem old_chapter = chapter # Add footer service_item.raw_footer.append(verses.format_verses()) @@ -734,7 +779,7 @@ class BibleMediaItem(MediaManagerItem): verses.add_version(second_version, second_copyright, second_permissions) service_item.raw_footer.append(verses.format_versions()) - raw_title.append(self.formatTitle(start_item, item)) + raw_title.append(self.formatTitle(start_item, bitem)) # If there are no more items we check whether we have to add bible_text. if bible_text: raw_slides.append(bible_text.lstrip()) @@ -757,9 +802,9 @@ class BibleMediaItem(MediaManagerItem): [service_item.add_from_text(slide[:30], slide) for slide in raw_slides] return True - def formatTitle(self, start_item, old_item): + def formatTitle(self, start_bitem, old_bitem): """ - This methode is called, when we have to change the title, because + This method is called, when we have to change the title, because we are at the end of a verse range. E. g. if we want to add Genesis 1:1-6 as well as Daniel 2:14. @@ -771,10 +816,8 @@ class BibleMediaItem(MediaManagerItem): """ verse_separator = get_reference_match(u'sep_v_display') range_separator = get_reference_match(u'sep_r_display') - old_bitem = self.listView.item(old_item.row()) old_chapter = self._decodeQtObject(old_bitem, 'chapter') old_verse = self._decodeQtObject(old_bitem, 'verse') - start_bitem = self.listView.item(start_item.row()) start_book = self._decodeQtObject(start_bitem, 'book') start_chapter = self._decodeQtObject(start_bitem, 'chapter') start_verse = self._decodeQtObject(start_bitem, 'verse') @@ -795,9 +838,9 @@ class BibleMediaItem(MediaManagerItem): range_separator + old_chapter + verse_separator + old_verse return u'%s %s (%s)' % (start_book, verse_range, bibles) - def checkTitle(self, item, old_item): + def checkTitle(self, bitem, old_bitem): """ - This methode checks if we are at the end of an verse range. If that is + This method checks if we are at the end of an verse range. If that is the case, we return True, otherwise False. E. g. if we added Genesis 1:1-6, but the next verse is Daniel 2:14, we return True. @@ -808,13 +851,11 @@ class BibleMediaItem(MediaManagerItem): The item we were previously dealing with. """ # Get all the necessary meta data. - bitem = self.listView.item(item.row()) book = self._decodeQtObject(bitem, 'book') chapter = int(self._decodeQtObject(bitem, 'chapter')) verse = int(self._decodeQtObject(bitem, 'verse')) bible = self._decodeQtObject(bitem, 'bible') second_bible = self._decodeQtObject(bitem, 'second_bible') - old_bitem = self.listView.item(old_item.row()) old_book = self._decodeQtObject(old_bitem, 'book') old_chapter = int(self._decodeQtObject(old_bitem, 'chapter')) old_verse = int(self._decodeQtObject(old_bitem, 'verse')) @@ -867,10 +908,21 @@ class BibleMediaItem(MediaManagerItem): return u'{su}[%s]{/su}' % verse_text return u'{su}%s{/su}' % verse_text - def onLayoutStyleComboBoxChanged(self): - self.settings.layout_style = self.quickLayoutComboBox.currentIndex() - self.settings.layoutStyleComboBox.setCurrentIndex( - self.settings.layout_style) - QtCore.QSettings().setValue( - self.settingsSection + u'/verse layout style', - QtCore.QVariant(self.settings.layout_style)) + def search(self, string): + """ + Search for some Bible verses (by reference). + """ + bible = unicode(self.quickVersionComboBox.currentText()) + search_results = self.parent.manager.get_verses(bible, string, False) + results = [] + if search_results: + versetext = u' '.join([verse.text for verse in search_results]) + return [[string, versetext]] + return [] + + def createItemFromId(self, item_id): + item = QtGui.QListWidgetItem() + bible = unicode(self.quickVersionComboBox.currentText()) + search_results = self.parent.manager.get_verses(bible, item_id, False) + items = self.buildDisplayResults(bible, u'', search_results) + return items diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 4bd3a8d4b..e05b56314 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -27,6 +27,7 @@ import logging from PyQt4 import QtCore, QtGui +from sqlalchemy.sql import or_, func from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ check_item_selected @@ -47,6 +48,7 @@ class CustomMediaItem(MediaManagerItem): MediaManagerItem.__init__(self, parent, self, icon) 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 @@ -161,4 +163,16 @@ class CustomMediaItem(MediaManagerItem): else: raw_footer.append(u'') service_item.raw_footer = raw_footer - return True \ No newline at end of file + return True + + 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) + results = [] + for custom in search_results: + results.append([custom.id, custom.title]) + return results diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 21b81128d..1377feef8 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -47,6 +47,7 @@ class ImageMediaItem(MediaManagerItem): self.IconPath = u'images/image' MediaManagerItem.__init__(self, parent, self, icon) self.quickPreviewAllowed = True + self.hasSearch = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged) @@ -130,51 +131,51 @@ class ImageMediaItem(MediaManagerItem): self.parent.formparent.finishedProgressBar() def generateSlideData(self, service_item, item=None, xmlVersion=False): - items = self.listView.selectedIndexes() - if items: - service_item.title = unicode(self.plugin.nameStrings[u'plural']) - service_item.add_capability(ItemCapabilities.AllowsMaintain) - service_item.add_capability(ItemCapabilities.AllowsPreview) - service_item.add_capability(ItemCapabilities.AllowsLoop) - service_item.add_capability(ItemCapabilities.AllowsAdditions) - # force a nonexistent theme - service_item.theme = -1 - missing_items = [] - missing_items_filenames = [] - for item in items: - bitem = self.listView.item(item.row()) - filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) - if not os.path.exists(filename): - missing_items.append(item) - missing_items_filenames.append(filename) - for item in missing_items: - items.remove(item) - # We cannot continue, as all images do not exist. - if not items: - critical_error_message_box( - translate('ImagePlugin.MediaItem', 'Missing Image(s)'), - unicode(translate('ImagePlugin.MediaItem', - 'The following image(s) no longer exist: %s')) % - u'\n'.join(missing_items_filenames)) - return False - # We have missing as well as existing images. We ask what to do. - elif missing_items and QtGui.QMessageBox.question(self, - translate('ImagePlugin.MediaItem', 'Missing Image(s)'), - unicode(translate('ImagePlugin.MediaItem', 'The following ' - 'image(s) no longer exist: %s\nDo you want to add the other ' - 'images anyway?')) % u'\n'.join(missing_items_filenames), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | - QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: - return False - # Continue with the existing images. - for item in items: - bitem = self.listView.item(item.row()) - filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) - (path, name) = os.path.split(filename) - service_item.add_from_image(filename, name) - return True + if item: + items = [item] else: + items = self.listView.selectedItems() + if not items: + return False + service_item.title = unicode(self.plugin.nameStrings[u'plural']) + service_item.add_capability(ItemCapabilities.AllowsMaintain) + service_item.add_capability(ItemCapabilities.AllowsPreview) + service_item.add_capability(ItemCapabilities.AllowsLoop) + service_item.add_capability(ItemCapabilities.AllowsAdditions) + # force a nonexistent theme + service_item.theme = -1 + missing_items = [] + missing_items_filenames = [] + for bitem in items: + filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) + if not os.path.exists(filename): + missing_items.append(item) + missing_items_filenames.append(filename) + for item in missing_items: + items.remove(item) + # We cannot continue, as all images do not exist. + if not items: + critical_error_message_box( + translate('ImagePlugin.MediaItem', 'Missing Image(s)'), + unicode(translate('ImagePlugin.MediaItem', + 'The following image(s) no longer exist: %s')) % + u'\n'.join(missing_items_filenames)) return False + # We have missing as well as existing images. We ask what to do. + elif missing_items and QtGui.QMessageBox.question(self, + translate('ImagePlugin.MediaItem', 'Missing Image(s)'), + unicode(translate('ImagePlugin.MediaItem', 'The following ' + 'image(s) no longer exist: %s\nDo you want to add the other ' + 'images anyway?')) % u'\n'.join(missing_items_filenames), + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | + QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: + return False + # Continue with the existing images. + for bitem in items: + filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) + (path, name) = os.path.split(filename) + service_item.add_from_image(filename, name) + return True def onResetClick(self): """ @@ -208,3 +209,14 @@ class ImageMediaItem(MediaManagerItem): unicode(translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' 'the image file "%s" no longer exists.')) % filename) + + def search(self, string): + list = SettingsManager.load_list(self.settingsSection, + self.settingsSection) + results = [] + string = string.lower() + for file in list: + filename = os.path.split(unicode(file))[1] + if filename.lower().find(string) > -1: + results.append([file, filename]) + return results diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index aa574d029..9f1d72f73 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -50,6 +50,7 @@ class MediaMediaItem(MediaManagerItem): u':/media/media_video.png').toImage() MediaManagerItem.__init__(self, parent, self, icon) self.singleServiceItem = False + self.hasSearch = True self.mediaObject = None QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'video_background_replaced'), @@ -212,3 +213,14 @@ class MediaMediaItem(MediaManagerItem): log.debug(u'CreatePhonon') if not self.mediaObject: self.mediaObject = Phonon.MediaObject(self) + + def search(self, string): + list = SettingsManager.load_list(self.settingsSection, + self.settingsSection) + results = [] + string = string.lower() + for file in list: + filename = os.path.split(unicode(file))[1] + if filename.lower().find(string) > -1: + results.append([file, filename]) + return results diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 65b85454d..7660c9099 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -53,6 +53,7 @@ class PresentationMediaItem(MediaManagerItem): self.Automatic = u'' MediaManagerItem.__init__(self, parent, self, icon) self.message_listener = MessageListener(self) + self.hasSearch = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) @@ -231,17 +232,19 @@ class PresentationMediaItem(MediaManagerItem): in the slidecontroller. In the case of powerpoints, an image for each slide """ - items = self.listView.selectedIndexes() - if len(items) > 1: - return False + if item: + items = [item] + else: + items = self.listView.selectedItems() + if len(items) > 1: + return False service_item.title = unicode(self.displayTypeComboBox.currentText()) service_item.shortname = unicode(self.displayTypeComboBox.currentText()) service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay) service_item.add_capability(ItemCapabilities.AllowsDetailedTitleDisplay) shortname = service_item.shortname if shortname: - for item in items: - bitem = self.listView.item(item.row()) + for bitem in items: filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) if os.path.exists(filename): if shortname == self.Automatic: @@ -303,3 +306,12 @@ class PresentationMediaItem(MediaManagerItem): if filetype in self.controllers[controller].alsosupports: return controller return None + + def search(self, string): + list = SettingsManager.load_list(self.settingsSection, u'presentations') + results = [] + string = string.lower() + for file in list: + if file.lower().find(string) > -1: + results.append([file, file]) + return results diff --git a/openlp/plugins/remotes/html/index.html b/openlp/plugins/remotes/html/index.html index 3708db654..fd7fb3715 100644 --- a/openlp/plugins/remotes/html/index.html +++ b/openlp/plugins/remotes/html/index.html @@ -43,6 +43,7 @@ Service Manager Slide Controller Alerts + Search
@@ -50,6 +51,7 @@
Back

Service Manager

+ Refresh
Blank - Unblank - Refresh - Previous + Show + Prev Next
@@ -67,6 +68,7 @@
Back

Slide Controller

+ Refresh
Blank - Unblank - Refresh - Previous + Show + Prev Next
@@ -93,5 +94,23 @@ Show Alert + diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 74463ffbc..4eee047a4 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -39,6 +39,19 @@ window.OpenLP = { } return $(targ); }, + getSearchablePlugins: function (event) { + $.getJSON( + "/api/plugin/search", + function (data, status) { + var select = $("#search-plugin"); + select.html(""); + $.each(data.results.items, function (idx, value) { + select.append(""); + }); + select.selectmenu("refresh"); + } + ); + }, loadService: function (event) { $.getJSON( "/api/service/list", @@ -63,7 +76,9 @@ 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]["text"]; + var text = data.results.slides[idx]["tag"]; + if (text != "") text = text + ": "; + text = text + data.results.slides[idx]["text"]; text = text.replace(/\n/g, '
'); var li = $("
  • ").append( $("").attr("value", parseInt(idx, 10)).html(text)); @@ -189,7 +204,43 @@ window.OpenLP = { } ); return false; + }, + search: function (event) { + var text = JSON.stringify({"request": {"text": $("#search-text").val()}}); + $.getJSON( + "/api/" + $("#search-plugin").val() + "/search", + {"data": text}, + function (data, status) { + var ul = $("#search > div[data-role=content] > ul[data-role=listview]"); + ul.html(""); + if (data.results.items.length == 0) { + var li = $("
  • ").text('No results'); + ul.append(li); + } + else { + $.each(data.results.items, function (idx, value) { + var li = $("
  • ").append( + $("").attr("value", value[0]).text(value[1])); + li.children("a").click(OpenLP.goLive); + ul.append(li); + }); + } + ul.listview("refresh"); + } + ); + return false; + }, + goLive: function (event) { + var slide = OpenLP.getElement(event); + var id = slide.attr("value"); + var text = JSON.stringify({"request": {"id": id}}); + $.getJSON( + "/api/" + $("#search-plugin").val() + "/live", + {"data": text}) + $.mobile.changePage("slide-controller"); + return false; } + } // Service Manager $("#service-manager").live("pagebeforeshow", OpenLP.loadService); @@ -207,7 +258,10 @@ $("#controller-blank").live("click", OpenLP.blankDisplay); $("#controller-unblank").live("click", OpenLP.unblankDisplay); // Alerts $("#alert-submit").live("click", OpenLP.showAlert); +// Search +$("#search-submit").live("click", OpenLP.search); // Poll the server twice a second to get any updates. +OpenLP.getSearchablePlugins(); $.ajaxSetup({ cache: false }); setInterval("OpenLP.pollServer();", 500); OpenLP.pollServer(); diff --git a/openlp/plugins/remotes/html/stage.html b/openlp/plugins/remotes/html/stage.html index 99090b6f9..9c74cc371 100644 --- a/openlp/plugins/remotes/html/stage.html +++ b/openlp/plugins/remotes/html/stage.html @@ -26,7 +26,7 @@ --> - OpenLP 2.0 Remote + OpenLP 2.0 Stage View diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 20005840c..351e7f905 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -123,7 +123,7 @@ except ImportError: from PyQt4 import QtCore, QtNetwork -from openlp.core.lib import Receiver +from openlp.core.lib import Receiver, PluginStatus from openlp.core.ui import HideMode from openlp.core.utils import AppLocation @@ -250,7 +250,10 @@ class HttpConnection(object): (r'^/api/controller/(live|preview)/(.*)$', self.controller), (r'^/api/service/(.*)$', self.service), (r'^/api/display/(hide|show)$', self.display), - (r'^/api/alert$', self.alert) + (r'^/api/alert$', self.alert), + (r'^/api/plugin/(search)$', self.pluginInfo), + (r'^/api/(.*)/search$', self.search), + (r'^/api/(.*)/live$', self.go_live) ] QtCore.QObject.connect(self.socket, QtCore.SIGNAL(u'readyRead()'), self.ready_read) @@ -409,8 +412,8 @@ class HttpConnection(object): item[u'html'] = unicode(frame[u'html']) else: item[u'tag'] = unicode(index + 1) - item[u'text'] = u'' - item[u'html'] = u'' + item[u'text'] = unicode(frame[u'title']) + item[u'html'] = unicode(frame[u'title']) item[u'selected'] = (self.parent.current_slide == index) data.append(item) json_data = {u'results': {u'slides': data}} @@ -443,6 +446,50 @@ class HttpConnection(object): return HttpResponse(json.dumps({u'results': {u'success': True}}), {u'Content-Type': u'application/json'}) + def pluginInfo(self, action): + """ + Return plugin related information, based on the action + + ``action`` - The action to perform + if 'search' return a list of plugin names which support search + """ + if action == u'search': + searches = [] + for plugin in self.parent.parent.pluginManager.plugins: + if plugin.status == PluginStatus.Active and \ + plugin.mediaItem and plugin.mediaItem.hasSearch: + searches.append(plugin.name) + return HttpResponse( + json.dumps({u'results': {u'items': searches}}), + {u'Content-Type': u'application/json'}) + + def search(self, type): + """ + Return a list of items that match the search text + + ``type`` + The plugin name to search in. + """ + text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] + plugin = self.parent.parent.pluginManager.get_plugin_by_name(type) + if plugin.status == PluginStatus.Active and \ + plugin.mediaItem and plugin.mediaItem.hasSearch: + results =plugin.mediaItem.search(text) + else: + results = [] + return HttpResponse( + json.dumps({u'results': {u'items': results}}), + {u'Content-Type': u'application/json'}) + + def go_live(self, type): + """ + Go live on an item of type ``type``. + """ + id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] + plugin = self.parent.parent.pluginManager.get_plugin_by_name(type) + if plugin.status == PluginStatus.Active and plugin.mediaItem: + plugin.mediaItem.goLive(id) + def send_response(self, response): http = u'HTTP/1.1 %s\r\n' % response.code for header, value in response.headers.iteritems(): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 3b014d4b0..59ee05b7a 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -32,7 +32,7 @@ from PyQt4 import QtCore, QtGui from sqlalchemy.sql import or_ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ - translate, check_item_selected, PluginStatus, check_search_result + translate, check_item_selected, PluginStatus from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ @@ -74,6 +74,7 @@ class SongMediaItem(MediaManagerItem): self.editItem = None self.whitespace = re.compile(r'\W+', re.UNICODE) self.quickPreviewAllowed = True + self.hasSearch = True def addEndHeaderBar(self): self.addToolbarSeparator() @@ -171,11 +172,7 @@ class SongMediaItem(MediaManagerItem): search_type = self.searchTextEdit.currentSearchType() if search_type == SongSearch.Entire: log.debug(u'Entire Song Search') - search_results = self.parent.manager.get_all_objects(Song, - or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ', - search_keywords.lower()) + u'%'), - Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'), - Song.comments.like(u'%' + search_keywords.lower() + u'%'))) + search_results = self.searchEntire(search_keywords) self.displayResultsSong(search_results) elif search_type == SongSearch.Titles: log.debug(u'Titles Search') @@ -199,7 +196,14 @@ class SongMediaItem(MediaManagerItem): search_results = self.parent.manager.get_all_objects(Song, Song.theme_name == search_keywords) self.displayResultsSong(search_results) - check_search_result(self.listView, search_results) + self.check_search_result() + + def searchEntire(self, search_keywords): + return self.parent.manager.get_all_objects(Song, + or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ', + search_keywords.lower()) + u'%'), + Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'), + Song.comments.like(u'%' + search_keywords.lower() + u'%'))) def onSongListLoad(self): """ @@ -217,7 +221,8 @@ class SongMediaItem(MediaManagerItem): # Push edits to the service manager to update items if self.editItem and self.updateServiceOnEdit and \ not self.remoteTriggered: - item = self.buildServiceItem(self.editItem) + item_id = _getIdOfItemToGenerate(self.editItem) + item = self.buildServiceItem(item_id) self.parent.serviceManager.replaceServiceItem(item) self.onRemoteEditClear() self.onSearchTextButtonClick() @@ -475,3 +480,13 @@ class SongMediaItem(MediaManagerItem): """ return locale.strcoll(unicode(song_1.title.lower()), unicode(song_2.title.lower())) + + def search(self, string): + """ + Search for some songs + """ + search_results = self.searchEntire(string) + results = [] + for song in search_results: + results.append([song.id, song.title]) + return results diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index f3c5705da..0091406d1 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -268,4 +268,3 @@ class SongsPlugin(Plugin): action_list.remove_action(self.songExportItem, UiStrings().Export) action_list.remove_action(self.toolsReindexItem, UiStrings().Tools) Plugin.finalise(self) -