2009-03-09 12:49:55 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
|
|
|
|
2009-09-08 19:58:05 +00:00
|
|
|
###############################################################################
|
|
|
|
# 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 #
|
2009-09-08 19:58:05 +00:00
|
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
# 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 #
|
|
|
|
###############################################################################
|
2009-03-09 12:49:55 +00:00
|
|
|
|
|
|
|
import logging
|
2010-12-09 15:08:04 +00:00
|
|
|
import locale
|
2011-05-30 11:17:23 +00:00
|
|
|
import re
|
2009-03-09 12:49:55 +00:00
|
|
|
|
|
|
|
from PyQt4 import QtCore, QtGui
|
2010-12-28 21:12:20 +00:00
|
|
|
from sqlalchemy.sql import or_
|
2009-08-04 20:23:33 +00:00
|
|
|
|
2011-02-10 18:38:03 +00:00
|
|
|
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
2011-05-15 12:11:08 +00:00
|
|
|
translate, check_item_selected, PluginStatus
|
2011-02-12 22:01:18 +00:00
|
|
|
from openlp.core.lib.searchedit import SearchEdit
|
2011-02-09 05:04:12 +00:00
|
|
|
from openlp.core.lib.ui import UiStrings
|
2010-04-02 12:23:40 +00:00
|
|
|
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
|
2011-01-23 16:05:46 +00:00
|
|
|
SongImportForm, SongExportForm
|
2011-06-01 22:47:42 +00:00
|
|
|
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
|
|
|
|
clean_string
|
2010-07-03 23:10:28 +00:00
|
|
|
from openlp.plugins.songs.lib.db import Author, Song
|
2011-02-11 21:17:56 +00:00
|
|
|
from openlp.plugins.songs.lib.ui import SongStrings
|
2009-06-03 15:38:14 +00:00
|
|
|
|
2010-02-27 15:31:23 +00:00
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2011-02-12 22:01:18 +00:00
|
|
|
class SongSearch(object):
|
|
|
|
"""
|
|
|
|
An enumeration for song search methods.
|
|
|
|
"""
|
|
|
|
Entire = 1
|
|
|
|
Titles = 2
|
|
|
|
Lyrics = 3
|
|
|
|
Authors = 4
|
|
|
|
Themes = 5
|
|
|
|
|
2011-02-25 17:27:06 +00:00
|
|
|
|
2009-03-09 12:49:55 +00:00
|
|
|
class SongMediaItem(MediaManagerItem):
|
|
|
|
"""
|
|
|
|
This is the custom media manager item for Songs.
|
|
|
|
"""
|
2009-06-07 19:34:24 +00:00
|
|
|
log.info(u'Song Media Item loaded')
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2010-09-15 17:55:27 +00:00
|
|
|
def __init__(self, parent, plugin, icon):
|
2009-09-26 07:13:59 +00:00
|
|
|
self.IconPath = u'songs/song'
|
2011-05-28 09:53:37 +00:00
|
|
|
MediaManagerItem.__init__(self, parent, plugin, icon)
|
2011-05-28 19:38:19 +00:00
|
|
|
self.edit_song_form = EditSongForm(self, self.plugin.formparent,
|
|
|
|
self.plugin.manager)
|
2011-05-28 09:53:37 +00:00
|
|
|
self.openLyrics = OpenLyrics(self.plugin.manager)
|
2010-04-06 19:16:14 +00:00
|
|
|
self.singleServiceItem = False
|
2009-09-15 18:56:56 +00:00
|
|
|
self.song_maintenance_form = SongMaintenanceForm(
|
2011-05-28 09:53:37 +00:00
|
|
|
self.plugin.manager, self)
|
2009-11-03 19:21:58 +00:00
|
|
|
# Holds information about whether the edit is remotly triggered and
|
|
|
|
# which Song is required.
|
2009-11-03 06:15:35 +00:00
|
|
|
self.remoteSong = -1
|
2010-10-06 19:27:30 +00:00
|
|
|
self.editItem = None
|
2011-04-02 09:52:32 +00:00
|
|
|
self.quickPreviewAllowed = True
|
2011-05-15 18:33:00 +00:00
|
|
|
self.hasSearch = True
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2009-09-26 07:13:59 +00:00
|
|
|
def addEndHeaderBar(self):
|
2009-07-18 05:43:50 +00:00
|
|
|
self.addToolbarSeparator()
|
2009-07-23 20:20:49 +00:00
|
|
|
## Song Maintenance Button ##
|
2011-01-05 16:50:28 +00:00
|
|
|
self.maintenanceAction = self.addToolbarButton(u'', u'',
|
2009-11-30 20:29:26 +00:00
|
|
|
':/songs/song_maintenance.png', self.onSongMaintenanceClick)
|
2011-01-05 16:50:28 +00:00
|
|
|
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)
|
2009-03-09 12:49:55 +00:00
|
|
|
# Signals and slots
|
2011-01-05 16:50:28 +00:00
|
|
|
QtCore.QObject.connect(self.searchTextEdit,
|
2009-10-16 18:41:41 +00:00
|
|
|
QtCore.SIGNAL(u'returnPressed()'), self.onSearchTextButtonClick)
|
2011-01-05 16:50:28 +00:00
|
|
|
QtCore.QObject.connect(self.searchTextButton,
|
2009-06-07 19:34:24 +00:00
|
|
|
QtCore.SIGNAL(u'pressed()'), self.onSearchTextButtonClick)
|
2011-01-05 16:50:28 +00:00
|
|
|
QtCore.QObject.connect(self.searchTextEdit,
|
2009-09-15 18:56:56 +00:00
|
|
|
QtCore.SIGNAL(u'textChanged(const QString&)'),
|
|
|
|
self.onSearchTextEditChanged)
|
2009-08-26 05:00:19 +00:00
|
|
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
2010-10-06 19:27:30 +00:00
|
|
|
QtCore.SIGNAL(u'songs_load_list'), self.onSongListLoad)
|
2009-10-17 05:47:17 +00:00
|
|
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
|
|
|
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
|
2009-10-24 13:07:41 +00:00
|
|
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
2010-04-16 07:31:01 +00:00
|
|
|
QtCore.SIGNAL(u'songs_preview'), self.onPreviewClick)
|
2009-10-29 09:18:26 +00:00
|
|
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
2010-04-16 07:31:01 +00:00
|
|
|
QtCore.SIGNAL(u'songs_edit'), self.onRemoteEdit)
|
2009-10-29 09:18:26 +00:00
|
|
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
2010-04-20 22:00:55 +00:00
|
|
|
QtCore.SIGNAL(u'songs_edit_clear'), self.onRemoteEditClear)
|
2011-01-05 16:50:28 +00:00
|
|
|
QtCore.QObject.connect(self.searchTextEdit,
|
2010-12-28 21:12:20 +00:00
|
|
|
QtCore.SIGNAL(u'cleared()'), self.onClearTextButtonClick)
|
2011-01-05 16:50:28 +00:00
|
|
|
QtCore.QObject.connect(self.searchTextEdit,
|
2010-12-28 21:12:20 +00:00
|
|
|
QtCore.SIGNAL(u'searchTypeChanged(int)'),
|
|
|
|
self.onSearchTextButtonClick)
|
2009-10-17 05:47:17 +00:00
|
|
|
|
2011-05-26 06:23:22 +00:00
|
|
|
def onFocus(self):
|
|
|
|
self.searchTextEdit.setFocus()
|
|
|
|
|
2009-10-17 05:47:17 +00:00
|
|
|
def configUpdated(self):
|
2010-04-27 16:27:57 +00:00
|
|
|
self.searchAsYouType = QtCore.QSettings().value(
|
2010-04-30 22:38:15 +00:00
|
|
|
self.settingsSection + u'/search as type',
|
2010-04-28 14:17:42 +00:00
|
|
|
QtCore.QVariant(u'False')).toBool()
|
2010-10-06 19:27:30 +00:00
|
|
|
self.updateServiceOnEdit = QtCore.QSettings().value(
|
|
|
|
self.settingsSection + u'/update service on edit',
|
|
|
|
QtCore.QVariant(u'False')).toBool()
|
2010-11-27 15:25:00 +00:00
|
|
|
self.addSongFromService = QtCore.QSettings().value(
|
2010-10-06 19:27:30 +00:00
|
|
|
self.settingsSection + u'/add song from service',
|
|
|
|
QtCore.QVariant(u'True')).toBool()
|
2009-08-26 05:00:19 +00:00
|
|
|
|
2009-03-09 12:49:55 +00:00
|
|
|
def retranslateUi(self):
|
2011-04-15 21:43:59 +00:00
|
|
|
self.searchTextLabel.setText(u'%s:' % UiStrings().Search)
|
|
|
|
self.searchTextButton.setText(UiStrings().Search)
|
2011-02-16 17:54:31 +00:00
|
|
|
self.maintenanceAction.setText(SongStrings.SongMaintenance)
|
2011-01-05 16:50:28 +00:00
|
|
|
self.maintenanceAction.setToolTip(translate('SongsPlugin.MediaItem',
|
2011-05-06 05:17:13 +00:00
|
|
|
'Maintain the lists of authors, topics and books.'))
|
2009-03-09 12:49:55 +00:00
|
|
|
|
|
|
|
def initialise(self):
|
2011-01-05 16:50:28 +00:00
|
|
|
self.searchTextEdit.setSearchTypes([
|
2011-02-12 22:01:18 +00:00
|
|
|
(SongSearch.Entire, u':/songs/song_search_all.png',
|
2010-12-31 08:41:00 +00:00
|
|
|
translate('SongsPlugin.MediaItem', 'Entire Song')),
|
2011-02-12 22:01:18 +00:00
|
|
|
(SongSearch.Titles, u':/songs/song_search_title.png',
|
2010-12-31 08:41:00 +00:00
|
|
|
translate('SongsPlugin.MediaItem', 'Titles')),
|
2011-02-12 22:01:18 +00:00
|
|
|
(SongSearch.Lyrics, u':/songs/song_search_lyrics.png',
|
2010-12-31 08:41:00 +00:00
|
|
|
translate('SongsPlugin.MediaItem', 'Lyrics')),
|
2011-02-12 22:01:18 +00:00
|
|
|
(SongSearch.Authors, u':/songs/song_search_author.png',
|
|
|
|
SongStrings.Authors),
|
2011-04-15 21:43:59 +00:00
|
|
|
(SongSearch.Themes, u':/slides/slide_theme.png', UiStrings().Themes)
|
2010-12-28 21:12:20 +00:00
|
|
|
])
|
2011-04-14 21:32:21 +00:00
|
|
|
self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value(
|
|
|
|
u'%s/last search type' % self.settingsSection,
|
|
|
|
QtCore.QVariant(SongSearch.Entire)).toInt()[0])
|
2009-10-17 05:47:17 +00:00
|
|
|
self.configUpdated()
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2009-06-21 17:45:59 +00:00
|
|
|
def onSearchTextButtonClick(self):
|
2011-04-15 12:55:56 +00:00
|
|
|
# Save the current search type to the configuration.
|
2011-04-14 21:32:21 +00:00
|
|
|
QtCore.QSettings().setValue(u'%s/last search type' %
|
|
|
|
self.settingsSection,
|
|
|
|
QtCore.QVariant(self.searchTextEdit.currentSearchType()))
|
|
|
|
# Reload the list considering the new search type.
|
2011-01-05 16:50:28 +00:00
|
|
|
search_keywords = unicode(self.searchTextEdit.displayText())
|
2009-09-21 23:11:50 +00:00
|
|
|
search_results = []
|
2011-01-05 16:50:28 +00:00
|
|
|
search_type = self.searchTextEdit.currentSearchType()
|
2011-02-12 22:01:18 +00:00
|
|
|
if search_type == SongSearch.Entire:
|
2010-12-28 21:12:20 +00:00
|
|
|
log.debug(u'Entire Song Search')
|
2011-05-14 09:48:58 +00:00
|
|
|
search_results = self.searchEntire(search_keywords)
|
2010-12-28 21:12:20 +00:00
|
|
|
self.displayResultsSong(search_results)
|
2011-02-12 22:01:18 +00:00
|
|
|
elif search_type == SongSearch.Titles:
|
2009-06-21 17:45:59 +00:00
|
|
|
log.debug(u'Titles Search')
|
2011-05-28 09:53:37 +00:00
|
|
|
search_results = self.plugin.manager.get_all_objects(Song,
|
2011-06-01 22:47:42 +00:00
|
|
|
Song.search_title.like(u'%' + clean_string(search_keywords) +
|
|
|
|
u'%'))
|
2009-06-21 17:45:59 +00:00
|
|
|
self.displayResultsSong(search_results)
|
2011-02-12 22:01:18 +00:00
|
|
|
elif search_type == SongSearch.Lyrics:
|
2009-06-21 17:45:59 +00:00
|
|
|
log.debug(u'Lyrics Search')
|
2011-05-28 09:53:37 +00:00
|
|
|
search_results = self.plugin.manager.get_all_objects(Song,
|
2011-06-01 22:47:42 +00:00
|
|
|
Song.search_lyrics.like(u'%' + clean_string(search_keywords) +
|
|
|
|
u'%'))
|
2009-06-21 17:45:59 +00:00
|
|
|
self.displayResultsSong(search_results)
|
2011-02-12 22:01:18 +00:00
|
|
|
elif search_type == SongSearch.Authors:
|
2009-06-21 17:45:59 +00:00
|
|
|
log.debug(u'Authors Search')
|
2011-05-28 09:53:37 +00:00
|
|
|
search_results = self.plugin.manager.get_all_objects(Author,
|
2010-07-18 23:37:24 +00:00
|
|
|
Author.display_name.like(u'%' + search_keywords + u'%'),
|
2010-06-30 22:05:51 +00:00
|
|
|
Author.display_name.asc())
|
2009-06-21 17:45:59 +00:00
|
|
|
self.displayResultsAuthor(search_results)
|
2011-02-12 22:01:18 +00:00
|
|
|
elif search_type == SongSearch.Themes:
|
2010-12-23 17:51:32 +00:00
|
|
|
log.debug(u'Theme Search')
|
2011-05-28 09:53:37 +00:00
|
|
|
search_results = self.plugin.manager.get_all_objects(Song,
|
2011-06-01 22:47:42 +00:00
|
|
|
Song.theme_name.like(u'%' + search_keywords + u'%'))
|
2010-12-23 17:51:32 +00:00
|
|
|
self.displayResultsSong(search_results)
|
2011-05-15 12:11:08 +00:00
|
|
|
self.check_search_result()
|
2010-10-06 19:27:30 +00:00
|
|
|
|
2011-05-14 09:48:58 +00:00
|
|
|
def searchEntire(self, search_keywords):
|
2011-05-28 09:53:37 +00:00
|
|
|
return self.plugin.manager.get_all_objects(Song,
|
2011-06-01 22:47:42 +00:00
|
|
|
or_(Song.search_title.like(u'%' + clean_string(search_keywords)
|
|
|
|
+ u'%'),
|
|
|
|
Song.search_lyrics.like(u'%' + clean_string(search_keywords)
|
|
|
|
+ u'%'),
|
2011-05-14 09:48:58 +00:00
|
|
|
Song.comments.like(u'%' + search_keywords.lower() + u'%')))
|
|
|
|
|
2010-10-06 19:27:30 +00:00
|
|
|
def onSongListLoad(self):
|
|
|
|
"""
|
|
|
|
Handle the exit from the edit dialog and trigger remote updates
|
|
|
|
of songs
|
|
|
|
"""
|
2011-03-08 16:46:53 +00:00
|
|
|
log.debug(u'onSongListLoad - start')
|
2010-10-06 19:27:30 +00:00
|
|
|
# Called to redisplay the song list screen edit from a search
|
2011-02-25 17:05:01 +00:00
|
|
|
# or from the exit of the Song edit dialog. If remote editing is active
|
2010-10-06 19:27:30 +00:00
|
|
|
# Trigger it and clean up so it will not update again.
|
2009-11-03 06:15:35 +00:00
|
|
|
if self.remoteTriggered == u'L':
|
|
|
|
self.onAddClick()
|
|
|
|
if self.remoteTriggered == u'P':
|
|
|
|
self.onPreviewClick()
|
2010-10-06 19:27:30 +00:00
|
|
|
# Push edits to the service manager to update items
|
2010-10-06 20:24:53 +00:00
|
|
|
if self.editItem and self.updateServiceOnEdit and \
|
|
|
|
not self.remoteTriggered:
|
2011-05-18 18:59:36 +00:00
|
|
|
item = self.buildServiceItem(self.editItem)
|
2011-05-28 09:53:37 +00:00
|
|
|
self.plugin.serviceManager.replaceServiceItem(item)
|
2009-11-03 06:15:35 +00:00
|
|
|
self.onRemoteEditClear()
|
2010-10-06 19:27:30 +00:00
|
|
|
self.onSearchTextButtonClick()
|
2011-03-08 16:46:53 +00:00
|
|
|
log.debug(u'onSongListLoad - finished')
|
2009-06-21 17:45:59 +00:00
|
|
|
|
|
|
|
def displayResultsSong(self, searchresults):
|
|
|
|
log.debug(u'display results Song')
|
2011-05-27 09:34:14 +00:00
|
|
|
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 songs by its title considering language specific characters.
|
2011-05-24 05:23:28 +00:00
|
|
|
# lower() is needed for windows!
|
2011-05-20 17:06:38 +00:00
|
|
|
searchresults.sort(
|
2011-05-23 10:34:42 +00:00
|
|
|
cmp=locale.strcoll, key=lambda song: song.title.lower())
|
2009-03-09 12:49:55 +00:00
|
|
|
for song in searchresults:
|
2011-02-25 16:29:03 +00:00
|
|
|
author_list = [author.display_name for author in song.authors]
|
2010-06-05 23:05:53 +00:00
|
|
|
song_title = unicode(song.title)
|
2011-02-25 16:29:03 +00:00
|
|
|
song_detail = u'%s (%s)' % (song_title, u', '.join(author_list))
|
2009-06-14 13:50:56 +00:00
|
|
|
song_name = QtGui.QListWidgetItem(song_detail)
|
|
|
|
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
2010-07-07 16:03:30 +00:00
|
|
|
self.listView.addItem(song_name)
|
2011-05-19 22:20:00 +00:00
|
|
|
# Auto-select the item if name has been set
|
2011-05-27 09:34:14 +00:00
|
|
|
if song.id == self.auto_select_id:
|
2011-05-19 22:20:00 +00:00
|
|
|
self.listView.setCurrentItem(song_name)
|
2011-05-27 09:34:14 +00:00
|
|
|
self.auto_select_id = -1
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2009-06-21 17:45:59 +00:00
|
|
|
def displayResultsAuthor(self, searchresults):
|
|
|
|
log.debug(u'display results Author')
|
2010-07-07 16:03:30 +00:00
|
|
|
self.listView.clear()
|
2009-06-21 17:45:59 +00:00
|
|
|
for author in searchresults:
|
|
|
|
for song in author.songs:
|
2010-12-31 02:17:41 +00:00
|
|
|
song_detail = u'%s (%s)' % (author.display_name, song.title)
|
2009-06-21 17:45:59 +00:00
|
|
|
song_name = QtGui.QListWidgetItem(song_detail)
|
|
|
|
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
2010-07-07 16:03:30 +00:00
|
|
|
self.listView.addItem(song_name)
|
2009-06-21 17:45:59 +00:00
|
|
|
|
2009-03-09 12:49:55 +00:00
|
|
|
def onClearTextButtonClick(self):
|
|
|
|
"""
|
|
|
|
Clear the search text.
|
|
|
|
"""
|
2011-01-05 16:50:28 +00:00
|
|
|
self.searchTextEdit.clear()
|
2010-06-18 22:09:41 +00:00
|
|
|
self.onSearchTextButtonClick()
|
2009-03-09 12:49:55 +00:00
|
|
|
|
|
|
|
def onSearchTextEditChanged(self, text):
|
2009-11-03 06:15:35 +00:00
|
|
|
"""
|
|
|
|
If search as type enabled invoke the search on each key press.
|
|
|
|
If the Lyrics are being searched do not start till 7 characters
|
|
|
|
have been entered.
|
|
|
|
"""
|
2009-10-17 05:47:17 +00:00
|
|
|
if self.searchAsYouType:
|
|
|
|
search_length = 1
|
2011-02-20 17:52:22 +00:00
|
|
|
if self.searchTextEdit.currentSearchType() == SongSearch.Entire:
|
2011-03-11 18:03:16 +00:00
|
|
|
search_length = 4
|
2011-03-09 18:14:50 +00:00
|
|
|
elif self.searchTextEdit.currentSearchType() == SongSearch.Lyrics:
|
2011-03-11 18:03:16 +00:00
|
|
|
search_length = 3
|
2009-10-17 05:47:17 +00:00
|
|
|
if len(text) > search_length:
|
|
|
|
self.onSearchTextButtonClick()
|
2011-03-09 18:14:50 +00:00
|
|
|
elif len(text) == 0:
|
|
|
|
self.onClearTextButtonClick()
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2010-04-02 12:23:40 +00:00
|
|
|
def onImportClick(self):
|
2010-08-22 19:50:30 +00:00
|
|
|
if not hasattr(self, u'import_wizard'):
|
2011-05-28 09:53:37 +00:00
|
|
|
self.import_wizard = SongImportForm(self, self.plugin)
|
2011-01-20 02:31:20 +00:00
|
|
|
if self.import_wizard.exec_() == QtGui.QDialog.Accepted:
|
|
|
|
Receiver.send_message(u'songs_load_list')
|
2010-04-02 12:23:40 +00:00
|
|
|
|
2011-01-23 16:05:46 +00:00
|
|
|
def onExportClick(self):
|
2011-05-28 09:53:37 +00:00
|
|
|
export_wizard = SongExportForm(self, self.plugin)
|
2011-03-14 18:59:59 +00:00
|
|
|
export_wizard.exec_()
|
2011-01-23 16:05:46 +00:00
|
|
|
|
2009-09-26 07:13:59 +00:00
|
|
|
def onNewClick(self):
|
2010-11-20 18:14:43 +00:00
|
|
|
log.debug(u'onNewClick')
|
2009-06-12 17:20:40 +00:00
|
|
|
self.edit_song_form.newSong()
|
2009-03-09 12:49:55 +00:00
|
|
|
self.edit_song_form.exec_()
|
2011-06-03 03:39:28 +00:00
|
|
|
self.onClearTextButtonClick()
|
2011-05-31 03:52:17 +00:00
|
|
|
self.onSelectionChange()
|
2011-06-03 03:39:28 +00:00
|
|
|
self.auto_select_id = -1
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2009-07-23 20:20:49 +00:00
|
|
|
def onSongMaintenanceClick(self):
|
|
|
|
self.song_maintenance_form.exec_()
|
|
|
|
|
2009-10-29 09:18:26 +00:00
|
|
|
def onRemoteEditClear(self):
|
2010-11-20 18:14:43 +00:00
|
|
|
log.debug(u'onRemoteEditClear')
|
2009-11-03 06:15:35 +00:00
|
|
|
self.remoteTriggered = None
|
|
|
|
self.remoteSong = -1
|
2009-10-29 09:18:26 +00:00
|
|
|
|
2011-04-10 18:44:27 +00:00
|
|
|
def onRemoteEdit(self, message):
|
2009-11-03 06:15:35 +00:00
|
|
|
"""
|
|
|
|
Called by ServiceManager or SlideController by event passing
|
|
|
|
the Song Id in the payload along with an indicator to say which
|
|
|
|
type of display is required.
|
|
|
|
"""
|
2011-04-10 18:44:27 +00:00
|
|
|
log.debug(u'onRemoteEdit %s' % message)
|
|
|
|
remote_type, song_id = message.split(u':')
|
|
|
|
song_id = int(song_id)
|
2011-05-28 09:53:37 +00:00
|
|
|
valid = self.plugin.manager.get_object(Song, song_id)
|
2009-11-03 19:01:53 +00:00
|
|
|
if valid:
|
2011-04-10 18:44:27 +00:00
|
|
|
self.remoteSong = song_id
|
|
|
|
self.remoteTriggered = remote_type
|
|
|
|
self.edit_song_form.loadSong(song_id, (remote_type == u'P'))
|
2009-10-29 09:18:26 +00:00
|
|
|
self.edit_song_form.exec_()
|
2011-05-31 03:52:17 +00:00
|
|
|
self.auto_select_id = -1
|
|
|
|
self.onSongListLoad()
|
2009-10-29 09:18:26 +00:00
|
|
|
|
2010-05-25 23:47:26 +00:00
|
|
|
def onEditClick(self):
|
2010-06-16 01:23:57 +00:00
|
|
|
"""
|
|
|
|
Edit a song
|
|
|
|
"""
|
2010-11-20 18:14:43 +00:00
|
|
|
log.debug(u'onEditClick')
|
2011-04-15 21:43:59 +00:00
|
|
|
if check_item_selected(self.listView, UiStrings().SelectEdit):
|
2010-10-06 19:27:30 +00:00
|
|
|
self.editItem = self.listView.currentItem()
|
|
|
|
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
|
2009-11-03 06:15:35 +00:00
|
|
|
self.edit_song_form.loadSong(item_id, False)
|
2009-06-19 18:41:38 +00:00
|
|
|
self.edit_song_form.exec_()
|
2011-05-31 03:52:17 +00:00
|
|
|
self.auto_select_id = -1
|
|
|
|
self.onSongListLoad()
|
2011-03-11 15:53:26 +00:00
|
|
|
self.editItem = None
|
2009-03-09 12:49:55 +00:00
|
|
|
|
2009-09-26 07:13:59 +00:00
|
|
|
def onDeleteClick(self):
|
2010-06-16 01:23:57 +00:00
|
|
|
"""
|
|
|
|
Remove a song from the list and database
|
|
|
|
"""
|
2011-04-15 21:43:59 +00:00
|
|
|
if check_item_selected(self.listView, UiStrings().SelectDelete):
|
2010-07-07 16:03:30 +00:00
|
|
|
items = self.listView.selectedIndexes()
|
2011-01-02 17:24:47 +00:00
|
|
|
if QtGui.QMessageBox.question(self,
|
2011-06-28 20:35:28 +00:00
|
|
|
UiStrings().ConfirmDelete,
|
2010-12-31 02:17:41 +00:00
|
|
|
translate('SongsPlugin.MediaItem',
|
|
|
|
'Are you sure you want to delete the %n selected song(s)?', '',
|
|
|
|
QtCore.QCoreApplication.CodecForTr, len(items)),
|
2011-06-28 19:05:05 +00:00
|
|
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
|
|
|
|
QtGui.QMessageBox.No),
|
|
|
|
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No:
|
2010-04-04 13:53:39 +00:00
|
|
|
return
|
2010-04-03 19:17:37 +00:00
|
|
|
for item in items:
|
2010-04-02 23:24:51 +00:00
|
|
|
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
2011-05-28 09:53:37 +00:00
|
|
|
self.plugin.manager.delete_object(Song, item_id)
|
2010-04-03 19:17:37 +00:00
|
|
|
self.onSearchTextButtonClick()
|
2009-06-03 15:38:14 +00:00
|
|
|
|
2010-11-27 15:25:00 +00:00
|
|
|
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
2010-11-20 18:14:43 +00:00
|
|
|
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
|
2011-02-01 00:33:50 +00:00
|
|
|
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
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)
|
2010-09-30 05:12:06 +00:00
|
|
|
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
|
|
|
service_item.add_capability(ItemCapabilities.AddIfNewItem)
|
2011-03-28 17:04:31 +00:00
|
|
|
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
|
2011-05-28 09:53:37 +00:00
|
|
|
song = self.plugin.manager.get_object(Song, item_id)
|
2009-06-14 13:50:56 +00:00
|
|
|
service_item.theme = song.theme_name
|
2010-11-20 18:14:43 +00:00
|
|
|
service_item.edit_id = item_id
|
2009-06-14 13:50:56 +00:00
|
|
|
if song.lyrics.startswith(u'<?xml version='):
|
2011-01-09 19:18:08 +00:00
|
|
|
verseList = SongXML().get_verses(song.lyrics)
|
2010-11-27 15:25:00 +00:00
|
|
|
# no verse list or only 1 space (in error)
|
2011-02-18 00:48:58 +00:00
|
|
|
verse_tags_translated = False
|
|
|
|
if VerseType.from_translated_string(unicode(
|
|
|
|
verseList[0][0][u'type'])) is not None:
|
|
|
|
verse_tags_translated = True
|
2011-02-17 15:05:58 +00:00
|
|
|
if not song.verse_order.strip():
|
2009-11-29 21:03:24 +00:00
|
|
|
for verse in verseList:
|
2011-02-17 19:46:01 +00:00
|
|
|
# We cannot use from_loose_input() here, because database
|
|
|
|
# is supposed to contain English lowercase singlechar tags.
|
2011-02-18 00:48:58 +00:00
|
|
|
verse_tag = verse[0][u'type']
|
|
|
|
verse_index = None
|
|
|
|
if len(verse_tag) > 1:
|
|
|
|
verse_index = \
|
|
|
|
VerseType.from_translated_string(verse_tag)
|
|
|
|
if verse_index is None:
|
|
|
|
verse_index = VerseType.from_string(verse_tag)
|
|
|
|
if verse_index is None:
|
|
|
|
verse_index = VerseType.from_tag(verse_tag)
|
|
|
|
verse_tag = VerseType.TranslatedTags[verse_index].upper()
|
|
|
|
verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
|
2010-06-12 20:22:58 +00:00
|
|
|
service_item.add_from_text(
|
2011-02-18 00:48:58 +00:00
|
|
|
verse[1][:30], unicode(verse[1]), verse_def)
|
2009-11-30 18:22:43 +00:00
|
|
|
else:
|
2010-11-20 18:14:43 +00:00
|
|
|
# Loop through the verse list and expand the song accordingly.
|
2011-02-17 15:05:58 +00:00
|
|
|
for order in song.verse_order.lower().split():
|
2009-12-05 08:05:11 +00:00
|
|
|
if len(order) == 0:
|
|
|
|
break
|
2009-11-30 18:22:43 +00:00
|
|
|
for verse in verseList:
|
2011-02-18 00:48:58 +00:00
|
|
|
if verse[0][u'type'][0].lower() == order[0] and \
|
|
|
|
(verse[0][u'label'].lower() == order[1:] or \
|
|
|
|
not order[1:]):
|
|
|
|
if verse_tags_translated:
|
|
|
|
verse_index = VerseType.from_translated_tag(
|
|
|
|
verse[0][u'type'])
|
|
|
|
else:
|
|
|
|
verse_index = VerseType.from_tag(
|
|
|
|
verse[0][u'type'])
|
|
|
|
if verse_index is None:
|
|
|
|
verse_index = VerseType.Other
|
|
|
|
verse_tag = VerseType.TranslatedTags[verse_index]
|
|
|
|
verse_def = u'%s%s' % (verse_tag,
|
2011-02-17 19:46:01 +00:00
|
|
|
verse[0][u'label'])
|
2010-06-12 20:22:58 +00:00
|
|
|
service_item.add_from_text(
|
2011-02-18 00:48:58 +00:00
|
|
|
verse[1][:30], verse[1], verse_def)
|
2009-06-14 13:50:56 +00:00
|
|
|
else:
|
|
|
|
verses = song.lyrics.split(u'\n\n')
|
|
|
|
for slide in verses:
|
2009-07-21 18:10:14 +00:00
|
|
|
service_item.add_from_text(slide[:30], unicode(slide))
|
2009-06-14 13:50:56 +00:00
|
|
|
service_item.title = song.title
|
2011-02-25 16:29:03 +00:00
|
|
|
author_list = [unicode(author.display_name) for author in song.authors]
|
2011-03-04 17:31:23 +00:00
|
|
|
service_item.raw_footer.append(song.title)
|
|
|
|
service_item.raw_footer.append(u', '.join(author_list))
|
|
|
|
service_item.raw_footer.append(song.copyright)
|
2011-02-06 19:53:08 +00:00
|
|
|
if QtCore.QSettings().value(u'general/ccli number',
|
|
|
|
QtCore.QVariant(u'')).toString():
|
2011-03-04 17:31:23 +00:00
|
|
|
service_item.raw_footer.append(unicode(
|
2011-02-06 19:53:08 +00:00
|
|
|
translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
|
|
|
QtCore.QSettings().value(u'general/ccli number',
|
|
|
|
QtCore.QVariant(u'')).toString()))
|
2009-10-30 17:44:16 +00:00
|
|
|
service_item.audit = [
|
2011-02-25 16:29:03 +00:00
|
|
|
song.title, author_list, song.copyright, unicode(song.ccli_number)
|
2009-10-30 17:44:16 +00:00
|
|
|
]
|
2011-01-02 17:24:47 +00:00
|
|
|
service_item.data_string = {u'title': song.search_title,
|
2011-02-25 16:29:03 +00:00
|
|
|
u'authors': u', '.join(author_list)}
|
2010-11-28 13:39:51 +00:00
|
|
|
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
2010-07-27 09:32:52 +00:00
|
|
|
return True
|
2010-09-30 05:12:06 +00:00
|
|
|
|
|
|
|
def serviceLoad(self, item):
|
|
|
|
"""
|
2011-03-14 18:59:59 +00:00
|
|
|
Triggered by a song being loaded by the service manager.
|
2010-09-30 05:12:06 +00:00
|
|
|
"""
|
2010-11-20 18:14:43 +00:00
|
|
|
log.debug(u'serviceLoad')
|
2011-02-05 23:52:05 +00:00
|
|
|
if self.plugin.status != PluginStatus.Active or not item.data_string:
|
|
|
|
return
|
2011-03-16 13:29:13 +00:00
|
|
|
if item.data_string[u'title'].find(u'@') == -1:
|
2011-03-16 17:21:03 +00:00
|
|
|
# This file seems to be an old one (prior to 1.9.5), which means,
|
|
|
|
# that the search title (data_string[u'title']) is probably wrong.
|
|
|
|
# We add "@" to search title and hope that we do not add any
|
|
|
|
# duplicate. This should work for songs without alternate title.
|
2011-05-28 09:53:37 +00:00
|
|
|
search_results = self.plugin.manager.get_all_objects(Song,
|
2011-03-16 13:29:13 +00:00
|
|
|
Song.search_title == (re.compile(r'\W+', re.UNICODE).sub(u' ',
|
2011-03-16 15:37:56 +00:00
|
|
|
item.data_string[u'title'].strip()) + u'@').strip().lower(),
|
2011-03-16 13:29:13 +00:00
|
|
|
Song.search_title.asc())
|
|
|
|
else:
|
2011-05-28 09:53:37 +00:00
|
|
|
search_results = self.plugin.manager.get_all_objects(Song,
|
2011-03-16 13:29:13 +00:00
|
|
|
Song.search_title == item.data_string[u'title'],
|
|
|
|
Song.search_title.asc())
|
2011-02-05 23:52:05 +00:00
|
|
|
editId = 0
|
|
|
|
add_song = True
|
|
|
|
if search_results:
|
|
|
|
for song in search_results:
|
2011-06-19 22:18:06 +00:00
|
|
|
author_list = item.data_string[u'authors']
|
2011-02-05 23:52:05 +00:00
|
|
|
same_authors = True
|
2011-06-19 22:18:06 +00:00
|
|
|
for author in song.authors:
|
|
|
|
if author.display_name in author_list:
|
|
|
|
author_list = author_list.replace(author.display_name,
|
|
|
|
u'', 1)
|
|
|
|
else:
|
|
|
|
same_authors = False
|
|
|
|
break
|
|
|
|
if same_authors and author_list.strip(u', ') == u'':
|
2011-02-05 23:52:05 +00:00
|
|
|
add_song = False
|
|
|
|
editId = song.id
|
|
|
|
break
|
2011-03-09 18:14:50 +00:00
|
|
|
if add_song and self.addSongFromService:
|
|
|
|
editId = self.openLyrics.xml_to_song(item.xml_version)
|
|
|
|
self.onSearchTextButtonClick()
|
2011-02-05 23:52:05 +00:00
|
|
|
# Update service with correct song id.
|
|
|
|
if editId:
|
|
|
|
Receiver.send_message(u'service_item_update',
|
|
|
|
u'%s:%s' % (editId, item._uuid))
|
2010-12-09 15:08:04 +00:00
|
|
|
|
2011-05-14 09:48:58 +00:00
|
|
|
def search(self, string):
|
|
|
|
"""
|
|
|
|
Search for some songs
|
|
|
|
"""
|
|
|
|
search_results = self.searchEntire(string)
|
2011-05-27 09:34:14 +00:00
|
|
|
return [[song.id, song.title] for song in search_results]
|