openlp/openlp/plugins/songs/forms/songmaintenanceform.py

511 lines
22 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2011-12-27 10:33:55 +00:00
# Copyright (c) 2008-2012 Raoul Snyman #
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
2011-05-26 16:25:54 +00:00
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
2011-05-26 17:11:22 +00:00
# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
2011-06-12 16:02:52 +00:00
# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
2011-06-12 15:41:01 +00:00
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
2011-01-15 00:53:12 +00:00
import logging
from PyQt4 import QtGui, QtCore
2010-07-12 13:18:07 +00:00
from sqlalchemy.sql import and_
2009-10-24 16:40:36 +00:00
from openlp.core.lib import Receiver, translate
2011-02-12 18:43:23 +00:00
from openlp.core.lib.ui import UiStrings, critical_error_message_box
2010-06-12 23:00:14 +00:00
from openlp.plugins.songs.forms import AuthorsForm, TopicsForm, SongBookForm
2010-07-19 07:54:57 +00:00
from openlp.plugins.songs.lib.db import Author, Book, Topic, Song
from songmaintenancedialog import Ui_SongMaintenanceDialog
2011-01-15 00:53:12 +00:00
log = logging.getLogger(__name__)
class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Class documentation goes here.
"""
def __init__(self, manager, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.manager = manager
self.authorform = AuthorsForm(self)
self.topicform = TopicsForm(self)
self.bookform = SongBookForm(self)
2011-01-19 20:27:43 +00:00
# Disable all edit and delete buttons, as there is no row selected.
self.authorsDeleteButton.setEnabled(False)
self.authorsEditButton.setEnabled(False)
self.topicsDeleteButton.setEnabled(False)
self.topicsEditButton.setEnabled(False)
self.booksDeleteButton.setEnabled(False)
self.booksEditButton.setEnabled(False)
# Signals
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.authorsAddButton,
QtCore.SIGNAL(u'clicked()'), self.onAuthorAddButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.topicsAddButton,
QtCore.SIGNAL(u'clicked()'), self.onTopicAddButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.booksAddButton,
QtCore.SIGNAL(u'clicked()'), self.onBookAddButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.authorsEditButton,
QtCore.SIGNAL(u'clicked()'), self.onAuthorEditButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.topicsEditButton,
QtCore.SIGNAL(u'clicked()'), self.onTopicEditButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.booksEditButton,
QtCore.SIGNAL(u'clicked()'), self.onBookEditButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.authorsDeleteButton,
QtCore.SIGNAL(u'clicked()'), self.onAuthorDeleteButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.topicsDeleteButton,
QtCore.SIGNAL(u'clicked()'), self.onTopicDeleteButtonClicked)
2011-01-04 21:06:50 +00:00
QtCore.QObject.connect(self.booksDeleteButton,
QtCore.SIGNAL(u'clicked()'), self.onBookDeleteButtonClicked)
2011-01-19 20:27:43 +00:00
QtCore.QObject.connect(self.authorsListWidget,
QtCore.SIGNAL(u'currentRowChanged(int)'),
self.onAuthorsListRowChanged)
QtCore.QObject.connect(self.topicsListWidget,
QtCore.SIGNAL(u'currentRowChanged(int)'),
self.onTopicsListRowChanged)
QtCore.QObject.connect(self.booksListWidget,
QtCore.SIGNAL(u'currentRowChanged(int)'),
self.onBooksListRowChanged)
def exec_(self):
2011-01-04 21:06:50 +00:00
self.typeListWidget.setCurrentRow(0)
self.resetAuthors()
self.resetTopics()
self.resetBooks()
2011-01-04 21:06:50 +00:00
self.typeListWidget.setFocus()
return QtGui.QDialog.exec_(self)
2011-02-01 18:05:59 +00:00
def _getCurrentItemId(self, listWidget):
item = listWidget.currentItem()
2009-11-03 19:01:53 +00:00
if item:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
return item_id
else:
return -1
2011-02-16 03:06:34 +00:00
def _deleteItem(self, item_class, list_widget, reset_func, dlg_title,
del_text, err_text):
item_id = self._getCurrentItemId(list_widget)
if item_id != -1:
item = self.manager.get_object(item_class, item_id)
if item and not item.songs:
2011-02-16 03:06:34 +00:00
if critical_error_message_box(dlg_title, del_text, self,
True) == QtGui.QMessageBox.Yes:
self.manager.delete_object(item_class, item.id)
reset_func()
else:
2011-02-16 03:06:34 +00:00
critical_error_message_box(dlg_title, err_text)
else:
critical_error_message_box(dlg_title, UiStrings().NISs)
def resetAuthors(self):
"""
Reloads the Authors list.
"""
2011-01-04 21:06:50 +00:00
self.authorsListWidget.clear()
authors = self.manager.get_all_objects(Author,
2010-07-18 23:37:24 +00:00
order_by_ref=Author.display_name)
for author in authors:
2009-11-03 19:01:53 +00:00
if author.display_name:
author_name = QtGui.QListWidgetItem(author.display_name)
else:
author_name = QtGui.QListWidgetItem(
2011-01-04 16:04:55 +00:00
u' '.join([author.first_name, author.last_name]))
author_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(author.id))
2011-01-04 21:06:50 +00:00
self.authorsListWidget.addItem(author_name)
def resetTopics(self):
"""
Reloads the Topics list.
"""
2011-01-04 21:06:50 +00:00
self.topicsListWidget.clear()
topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
for topic in topics:
topic_name = QtGui.QListWidgetItem(topic.name)
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
2011-01-04 21:06:50 +00:00
self.topicsListWidget.addItem(topic_name)
def resetBooks(self):
"""
Reloads the Books list.
"""
2011-01-04 21:06:50 +00:00
self.booksListWidget.clear()
books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
for book in books:
book_name = QtGui.QListWidgetItem(u'%s (%s)' % (book.name,
book.publisher))
book_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(book.id))
2011-01-04 21:06:50 +00:00
self.booksListWidget.addItem(book_name)
2010-07-10 17:30:01 +00:00
def checkAuthor(self, new_author, edit=False):
"""
2011-01-19 20:27:43 +00:00
Returns *False* if the given Author already exists, otherwise *True*.
"""
authors = self.manager.get_all_objects(Author,
and_(Author.first_name == new_author.first_name,
Author.last_name == new_author.last_name,
Author.display_name == new_author.display_name))
2011-02-03 01:55:12 +00:00
return self.__checkObject(authors, new_author, edit)
def checkTopic(self, new_topic, edit=False):
"""
2011-01-19 20:27:43 +00:00
Returns *False* if the given Topic already exists, otherwise *True*.
"""
topics = self.manager.get_all_objects(Topic,
2010-07-16 18:53:49 +00:00
Topic.name == new_topic.name)
2011-02-03 01:55:12 +00:00
return self.__checkObject(topics, new_topic, edit)
2010-07-10 17:30:01 +00:00
def checkBook(self, new_book, edit=False):
"""
2011-01-19 20:27:43 +00:00
Returns *False* if the given Topic already exists, otherwise *True*.
"""
books = self.manager.get_all_objects(Book,
and_(Book.name == new_book.name,
2010-07-16 18:53:49 +00:00
Book.publisher == new_book.publisher))
2011-02-03 01:55:12 +00:00
return self.__checkObject(books, new_book, edit)
def __checkObject(self, objects, new_object, edit):
"""
Utility method to check for an existing object.
``edit``
If we edit an item, this should be *True*.
"""
if objects:
2011-02-03 01:55:12 +00:00
# If we edit an existing object, we need to make sure that we do
2011-01-19 20:27:43 +00:00
# not return False when nothing has changed.
2010-07-16 18:53:49 +00:00
if edit:
2011-02-03 01:55:12 +00:00
for object in objects:
if object.id != new_object.id:
2011-01-19 03:46:53 +00:00
return False
return True
2010-07-16 18:53:49 +00:00
else:
return False
2010-07-12 13:18:07 +00:00
else:
return True
def onAuthorAddButtonClicked(self):
self.authorform.setAutoDisplayName(True)
if self.authorform.exec_():
author = Author.populate(
2011-01-04 21:06:50 +00:00
first_name=unicode(self.authorform.firstNameEdit.text()),
last_name=unicode(self.authorform.lastNameEdit.text()),
display_name=unicode(self.authorform.displayEdit.text()))
2010-07-12 13:18:07 +00:00
if self.checkAuthor(author):
if self.manager.save_object(author):
2010-07-12 13:18:07 +00:00
self.resetAuthors()
2010-07-16 09:00:20 +00:00
else:
2011-02-16 03:06:34 +00:00
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not add your author.'))
else:
critical_error_message_box(
2011-02-16 03:06:34 +00:00
message=translate('SongsPlugin.SongMaintenanceForm',
'This author already exists.'))
def onTopicAddButtonClicked(self):
if self.topicform.exec_():
2011-01-04 21:06:50 +00:00
topic = Topic.populate(name=unicode(self.topicform.nameEdit.text()))
2010-07-12 13:18:07 +00:00
if self.checkTopic(topic):
if self.manager.save_object(topic):
2010-07-12 13:18:07 +00:00
self.resetTopics()
2010-07-16 09:00:20 +00:00
else:
2011-02-16 03:06:34 +00:00
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not add your topic.'))
else:
critical_error_message_box(
2011-02-16 03:06:34 +00:00
message=translate('SongsPlugin.SongMaintenanceForm',
'This topic already exists.'))
def onBookAddButtonClicked(self):
if self.bookform.exec_():
2011-01-04 21:06:50 +00:00
book = Book.populate(name=unicode(self.bookform.nameEdit.text()),
publisher=unicode(self.bookform.publisherEdit.text()))
2010-07-12 13:18:07 +00:00
if self.checkBook(book):
if self.manager.save_object(book):
2010-07-12 13:18:07 +00:00
self.resetBooks()
2010-07-16 09:00:20 +00:00
else:
2011-02-16 03:06:34 +00:00
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not add your book.'))
else:
critical_error_message_box(
2011-02-16 03:06:34 +00:00
message=translate('SongsPlugin.SongMaintenanceForm',
'This book already exists.'))
def onAuthorEditButtonClicked(self):
2011-01-04 21:06:50 +00:00
author_id = self._getCurrentItemId(self.authorsListWidget)
if author_id == -1:
return
author = self.manager.get_object(Author, author_id)
self.authorform.setAutoDisplayName(False)
self.authorform.firstNameEdit.setText(author.first_name)
self.authorform.lastNameEdit.setText(author.last_name)
self.authorform.displayEdit.setText(author.display_name)
# Save the author's first and last name as well as the display name
# for the case that they have to be restored.
temp_first_name = author.first_name
temp_last_name = author.last_name
temp_display_name = author.display_name
if self.authorform.exec_(False):
2011-02-13 16:02:12 +00:00
author.first_name = unicode(self.authorform.firstNameEdit.text())
author.last_name = unicode(self.authorform.lastNameEdit.text())
2011-02-13 16:02:12 +00:00
author.display_name = unicode(self.authorform.displayEdit.text())
if self.checkAuthor(author, True):
if self.manager.save_object(author):
self.resetAuthors()
Receiver.send_message(u'songs_load_list')
else:
critical_error_message_box(
2011-01-15 19:24:50 +00:00
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not save your changes.'))
elif critical_error_message_box(message=unicode(translate(
'SongsPlugin.SongMaintenanceForm', 'The author %s already '
'exists. Would you like to make songs with author %s use '
'the existing author %s?')) % (author.display_name,
temp_display_name, author.display_name),
parent=self, question=True) == QtGui.QMessageBox.Yes:
2011-02-01 00:33:50 +00:00
self.__mergeObjects(author, self.mergeAuthors,
self.resetAuthors)
else:
# We restore the author's old first and last name as well as
# his display name.
author.first_name = temp_first_name
author.last_name = temp_last_name
author.display_name = temp_display_name
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not save your modified author, because the '
'author already exists.'))
def onTopicEditButtonClicked(self):
2011-01-04 21:06:50 +00:00
topic_id = self._getCurrentItemId(self.topicsListWidget)
if topic_id == -1:
return
topic = self.manager.get_object(Topic, topic_id)
self.topicform.nameEdit.setText(topic.name)
# Save the topic's name for the case that he has to be restored.
temp_name = topic.name
if self.topicform.exec_(False):
topic.name = unicode(self.topicform.nameEdit.text())
if self.checkTopic(topic, True):
if self.manager.save_object(topic):
self.resetTopics()
else:
critical_error_message_box(
2011-01-15 19:24:50 +00:00
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not save your changes.'))
elif critical_error_message_box(
message=unicode(translate('SongsPlugin.SongMaintenanceForm',
'The topic %s already exists. Would you like to make songs '
'with topic %s use the existing topic %s?')) % (topic.name,
temp_name, topic.name),
parent=self, question=True) == QtGui.QMessageBox.Yes:
2011-02-01 00:33:50 +00:00
self.__mergeObjects(topic, self.mergeTopics, self.resetTopics)
else:
# We restore the topics's old name.
topic.name = temp_name
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not save your modified topic, because it '
'already exists.'))
def onBookEditButtonClicked(self):
2011-01-04 21:06:50 +00:00
book_id = self._getCurrentItemId(self.booksListWidget)
if book_id == -1:
return
book = self.manager.get_object(Book, book_id)
if book.publisher is None:
book.publisher = u''
self.bookform.nameEdit.setText(book.name)
self.bookform.publisherEdit.setText(book.publisher)
# Save the book's name and publisher for the case that they have to
# be restored.
temp_name = book.name
temp_publisher = book.publisher
if self.bookform.exec_(False):
book.name = unicode(self.bookform.nameEdit.text())
book.publisher = unicode(self.bookform.publisherEdit.text())
if self.checkBook(book, True):
if self.manager.save_object(book):
self.resetBooks()
else:
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'Could not save your changes.'))
elif critical_error_message_box(
message=unicode(translate('SongsPlugin.SongMaintenanceForm',
'The book %s already exists. Would you like to make songs '
'with book %s use the existing book %s?')) % (book.name,
temp_name, book.name),
parent=self, question=True) == QtGui.QMessageBox.Yes:
2011-02-01 00:33:50 +00:00
self.__mergeObjects(book, self.mergeBooks, self.resetBooks)
else:
# We restore the book's old name and publisher.
book.name = temp_name
book.publisher = temp_publisher
2011-02-01 18:05:59 +00:00
def __mergeObjects(self, dbObject, merge, reset):
2011-02-01 00:33:50 +00:00
"""
Utility method to merge two objects to leave one in the database.
"""
Receiver.send_message(u'cursor_busy')
2011-02-01 18:05:59 +00:00
merge(dbObject)
2011-02-01 00:33:50 +00:00
reset()
Receiver.send_message(u'songs_load_list')
Receiver.send_message(u'cursor_normal')
2010-07-19 13:39:18 +00:00
def mergeAuthors(self, old_author):
"""
2010-07-17 15:10:46 +00:00
Merges two authors into one author.
2010-07-19 13:39:18 +00:00
``old_author``
2011-01-20 05:42:44 +00:00
The object, which was edited, that will be deleted
"""
2011-01-19 20:27:43 +00:00
# Find the duplicate.
existing_author = self.manager.get_object_filtered(Author,
2010-07-19 13:39:18 +00:00
and_(Author.first_name == old_author.first_name,
2010-12-13 14:24:16 +00:00
Author.last_name == old_author.last_name,
Author.display_name == old_author.display_name,
Author.id != old_author.id))
2011-01-19 20:27:43 +00:00
# Find the songs, which have the old_author as author.
songs = self.manager.get_all_objects(Song,
2010-07-19 14:56:24 +00:00
Song.authors.contains(old_author))
for song in songs:
2010-07-19 14:56:24 +00:00
# We check if the song has already existing_author as author. If
# that is not the case we add it.
if existing_author not in song.authors:
song.authors.append(existing_author)
song.authors.remove(old_author)
self.manager.save_object(song)
self.manager.delete_object(Author, old_author.id)
2010-07-19 13:39:18 +00:00
def mergeTopics(self, old_topic):
"""
2010-07-17 15:10:46 +00:00
Merges two topics into one topic.
2010-07-19 13:39:18 +00:00
``old_topic``
2011-01-20 05:42:44 +00:00
The object, which was edited, that will be deleted
"""
2011-01-19 20:27:43 +00:00
# Find the duplicate.
existing_topic = self.manager.get_object_filtered(Topic,
and_(Topic.name == old_topic.name, Topic.id != old_topic.id))
2011-01-19 20:27:43 +00:00
# Find the songs, which have the old_topic as topic.
songs = self.manager.get_all_objects(Song,
2010-07-19 14:56:24 +00:00
Song.topics.contains(old_topic))
for song in songs:
2010-07-19 14:56:24 +00:00
# We check if the song has already existing_topic as topic. If that
# is not the case we add it.
if existing_topic not in song.topics:
song.topics.append(existing_topic)
song.topics.remove(old_topic)
self.manager.save_object(song)
self.manager.delete_object(Topic, old_topic.id)
2010-07-19 13:39:18 +00:00
def mergeBooks(self, old_book):
"""
2010-07-17 15:10:46 +00:00
Merges two books into one book.
2010-07-19 13:39:18 +00:00
``old_book``
2011-01-20 05:42:44 +00:00
The object, which was edited, that will be deleted
"""
2011-01-19 20:27:43 +00:00
# Find the duplicate.
existing_book = self.manager.get_object_filtered(Book,
2010-07-19 13:39:18 +00:00
and_(Book.name == old_book.name,
Book.publisher == old_book.publisher,
Book.id != old_book.id))
2011-01-19 20:27:43 +00:00
# Find the songs, which have the old_book as book.
songs = self.manager.get_all_objects(Song,
2010-07-19 13:39:18 +00:00
Song.song_book_id == old_book.id)
for song in songs:
2010-07-19 13:39:18 +00:00
song.song_book_id = existing_book.id
self.manager.save_object(song)
self.manager.delete_object(Book, old_book.id)
def onAuthorDeleteButtonClicked(self):
"""
Delete the author if the author is not attached to any songs.
"""
2011-01-04 21:06:50 +00:00
self._deleteItem(Author, self.authorsListWidget, self.resetAuthors,
2011-02-16 03:06:34 +00:00
translate('SongsPlugin.SongMaintenanceForm', 'Delete Author'),
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected author?'),
translate('SongsPlugin.SongMaintenanceForm', 'This author cannot '
'be deleted, they are currently assigned to at least one song.'))
def onTopicDeleteButtonClicked(self):
"""
2011-02-12 18:43:23 +00:00
Delete the Book if the Book is not attached to any songs.
"""
2011-01-04 21:06:50 +00:00
self._deleteItem(Topic, self.topicsListWidget, self.resetTopics,
2011-02-16 03:06:34 +00:00
translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'),
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected topic?'),
translate('SongsPlugin.SongMaintenanceForm', 'This topic cannot '
'be deleted, it is currently assigned to at least one song.'))
def onBookDeleteButtonClicked(self):
"""
2011-02-12 18:43:23 +00:00
Delete the Book if the Book is not attached to any songs.
"""
2011-01-04 21:06:50 +00:00
self._deleteItem(Book, self.booksListWidget, self.resetBooks,
2011-02-16 03:06:34 +00:00
translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'),
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected book?'),
translate('SongsPlugin.SongMaintenanceForm', 'This book cannot be '
'deleted, it is currently assigned to at least one song.'))
2011-01-19 20:27:43 +00:00
def onAuthorsListRowChanged(self, row):
"""
2011-02-03 17:28:48 +00:00
Called when the *authorsListWidget*'s current row has changed.
2011-01-19 20:27:43 +00:00
"""
2011-02-01 00:33:50 +00:00
self.__rowChange(row, self.authorsEditButton, self.authorsDeleteButton)
2011-01-19 20:27:43 +00:00
def onTopicsListRowChanged(self, row):
"""
2011-02-03 17:28:48 +00:00
Called when the *topicsListWidget*'s current row has changed.
2011-01-19 20:27:43 +00:00
"""
2011-02-01 00:33:50 +00:00
self.__rowChange(row, self.topicsEditButton, self.topicsDeleteButton)
2011-01-19 20:27:43 +00:00
def onBooksListRowChanged(self, row):
"""
2011-02-03 17:28:48 +00:00
Called when the *booksListWidget*'s current row has changed.
2011-02-01 00:33:50 +00:00
"""
self.__rowChange(row, self.booksEditButton, self.booksDeleteButton)
def __rowChange(self, row, editButton, deleteButton):
"""
Utility method to toggle if buttons are enabled.
2011-01-19 20:27:43 +00:00
``row``
The current row. If there is no current row, the value is -1.
"""
if row == -1:
2011-02-01 00:33:50 +00:00
deleteButton.setEnabled(False)
editButton.setEnabled(False)
2011-01-19 20:27:43 +00:00
else:
2011-02-01 00:33:50 +00:00
deleteButton.setEnabled(True)
editButton.setEnabled(True)