Allow the user to remove tags from the database from the tag editor

This commit is contained in:
Kovid Goyal 2008-01-20 06:55:59 +00:00
parent 45d418f874
commit 5b276ee524
3 changed files with 228 additions and 156 deletions

View File

@ -13,10 +13,11 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtCore import SIGNAL, Qt
from PyQt4.QtGui import QDialog from PyQt4.QtGui import QDialog, QMessageBox
from libprs500.gui2.dialogs.tag_editor_ui import Ui_TagEditor from libprs500.gui2.dialogs.tag_editor_ui import Ui_TagEditor
from libprs500.gui2 import qstring_to_unicode from libprs500.gui2 import qstring_to_unicode
from libprs500.gui2 import question_dialog
class TagEditor(QDialog, Ui_TagEditor): class TagEditor(QDialog, Ui_TagEditor):
@ -45,12 +46,34 @@ class TagEditor(QDialog, Ui_TagEditor):
if tag not in tags: if tag not in tags:
self.available_tags.addItem(tag) self.available_tags.addItem(tag)
self.connect(self.apply_button, SIGNAL('clicked()'), self.apply_tags) self.connect(self.apply_button, SIGNAL('clicked()'), self.apply_tags)
self.connect(self.unapply_button, SIGNAL('clicked()'), self.unapply_tags) self.connect(self.unapply_button, SIGNAL('clicked()'), self.unapply_tags)
self.connect(self.add_tag_button, SIGNAL('clicked()'), self.add_tag) self.connect(self.add_tag_button, SIGNAL('clicked()'), self.add_tag)
self.connect(self.add_tag_input, SIGNAL('returnPressed()'), self.add_tag) self.connect(self.delete_button, SIGNAL('clicked()'), self.delete_tags)
self.connect(self.add_tag_input, SIGNAL('returnPressed()'), self.add_tag)
self.connect(self.available_tags, SIGNAL('itemActivated(QListWidgetItem*)'), self.apply_tags) self.connect(self.available_tags, SIGNAL('itemActivated(QListWidgetItem*)'), self.apply_tags)
self.connect(self.applied_tags, SIGNAL('itemActivated(QListWidgetItem*)'), self.unapply_tags) self.connect(self.applied_tags, SIGNAL('itemActivated(QListWidgetItem*)'), self.unapply_tags)
def delete_tags(self, item=None):
confirms, deletes = [], []
items = self.available_tags.selectedItems() if item is None else [item]
for item in items:
if self.db.is_tag_used(qstring_to_unicode(item.text())):
confirms.append(item)
else:
deletes.append(item)
if confirms:
ct = ', '.join([qstring_to_unicode(item.text()) for item in confirms])
d = question_dialog(self, 'Are your sure?',
'<p>The following tags are used by one or more books. Are you certain you want to delete them?<br>'+ct)
if d.exec_() == QMessageBox.Yes:
deletes += confirms
for item in deletes:
self.db.delete_tag(qstring_to_unicode(item.text()))
self.available_tags.takeItem(self.available_tags.row(item))
def apply_tags(self, item=None): def apply_tags(self, item=None):
items = self.available_tags.selectedItems() if item is None else [item] items = self.available_tags.selectedItems() if item is None else [item]

View File

@ -17,35 +17,48 @@
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout" >
<item row="0" column="0" > <item row="0" column="0" >
<layout class="QHBoxLayout" > <layout class="QVBoxLayout" >
<item> <item>
<layout class="QVBoxLayout" > <layout class="QHBoxLayout" >
<item> <item>
<layout class="QHBoxLayout" > <widget class="QLabel" name="label" >
<item> <property name="text" >
<widget class="QLabel" name="label" > <string>A&amp;vailable tags</string>
<property name="text" > </property>
<string>A&amp;vailable tags</string> <property name="buddy" >
</property> <cstring>available_tags</cstring>
<property name="buddy" > </property>
<cstring>available_tags</cstring> </widget>
</property> </item>
</widget> <item>
</item> <spacer>
<item> <property name="orientation" >
<spacer> <enum>Qt::Horizontal</enum>
<property name="orientation" > </property>
<enum>Qt::Horizontal</enum> <property name="sizeHint" >
</property> <size>
<property name="sizeHint" > <width>40</width>
<size> <height>20</height>
<width>40</width> </size>
<height>20</height> </property>
</size> </spacer>
</property> </item>
</spacer> </layout>
</item> </item>
</layout> <item>
<layout class="QHBoxLayout" >
<item>
<widget class="QToolButton" name="delete_button" >
<property name="toolTip" >
<string>Delete tag from database. This will unapply the tag from all books and then remove it from the database.</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >:/images/trash.svg</iconset>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QListWidget" name="available_tags" > <widget class="QListWidget" name="available_tags" >
@ -62,136 +75,136 @@
</item> </item>
</layout> </layout>
</item> </item>
</layout>
</item>
<item row="0" column="1" >
<layout class="QVBoxLayout" >
<item> <item>
<layout class="QVBoxLayout" > <spacer>
<item> <property name="orientation" >
<spacer> <enum>Qt::Vertical</enum>
<property name="orientation" > </property>
<enum>Qt::Vertical</enum> <property name="sizeHint" >
</property> <size>
<property name="sizeHint" > <width>20</width>
<size> <height>40</height>
<width>20</width> </size>
<height>40</height> </property>
</size> </spacer>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="apply_button" >
<property name="toolTip" >
<string>Apply tag to current book</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >:/images/forward.svg</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" > <widget class="QToolButton" name="apply_button" >
<item> <property name="toolTip" >
<layout class="QHBoxLayout" > <string>Apply tag to current book</string>
<item> </property>
<widget class="QLabel" name="label_2" > <property name="text" >
<property name="text" > <string>...</string>
<string>A&amp;pplied tags</string> </property>
</property> <property name="icon" >
<property name="buddy" > <iconset resource="../images.qrc" >:/images/forward.svg</iconset>
<cstring>applied_tags</cstring> </property>
</property> </widget>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="applied_tags" >
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" > <spacer>
<item> <property name="orientation" >
<spacer> <enum>Qt::Vertical</enum>
<property name="orientation" > </property>
<enum>Qt::Vertical</enum> <property name="sizeHint" >
</property> <size>
<property name="sizeHint" > <width>20</width>
<size> <height>40</height>
<width>20</width> </size>
<height>40</height> </property>
</size> </spacer>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="unapply_button" >
<property name="toolTip" >
<string>Unapply (remove) tag from current book</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >:/images/list_remove.svg</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="0" > <item row="0" column="2" >
<layout class="QVBoxLayout" >
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>A&amp;pplied tags</string>
</property>
<property name="buddy" >
<cstring>applied_tags</cstring>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="applied_tags" >
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="3" >
<layout class="QVBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="unapply_button" >
<property name="toolTip" >
<string>Unapply (remove) tag from current book</string>
</property>
<property name="text" >
<string>...</string>
</property>
<property name="icon" >
<iconset resource="../images.qrc" >:/images/list_remove.svg</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0" colspan="4" >
<layout class="QHBoxLayout" > <layout class="QHBoxLayout" >
<item> <item>
<spacer> <spacer>
@ -251,7 +264,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="2" column="0" > <item row="2" column="0" colspan="4" >
<widget class="QDialogButtonBox" name="buttonBox" > <widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" > <property name="orientation" >
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>

View File

@ -377,7 +377,7 @@ class LibraryDatabase(object):
BEFORE DELETE ON tags BEFORE DELETE ON tags
BEGIN BEGIN
SELECT CASE SELECT CASE
WHEN (SELECT COUNT(id) FROM books_tags_link WHERE book=OLD.book) > 0 WHEN (SELECT COUNT(id) FROM books_tags_link WHERE tag=OLD.book) > 0
THEN RAISE(ABORT, 'Foreign key violation: tag is still referenced') THEN RAISE(ABORT, 'Foreign key violation: tag is still referenced')
END; END;
END; END;
@ -722,7 +722,23 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
''') ''')
conn.execute('pragma user_version=5') conn.execute('pragma user_version=5')
conn.commit() conn.commit()
@staticmethod
def upgrade_version5(conn):
conn.executescript(\
'''
DROP TRIGGER fkc_delete_books_tags_link;
CREATE TRIGGER fkc_delete_books_tags_link
BEFORE DELETE ON tags
BEGIN
SELECT CASE
WHEN (SELECT COUNT(id) FROM books_tags_link WHERE tag=OLD.id) > 0
THEN RAISE(ABORT, 'Foreign key violation: tag is still referenced')
END;
END;
''')
conn.execute('pragma user_version=6')
conn.commit()
def __del__(self): def __del__(self):
global _lock_file global _lock_file
@ -747,6 +763,8 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
LibraryDatabase.upgrade_version3(self.conn) LibraryDatabase.upgrade_version3(self.conn)
if self.user_version == 4: # Upgrade to 5 if self.user_version == 4: # Upgrade to 5
LibraryDatabase.upgrade_version4(self.conn) LibraryDatabase.upgrade_version4(self.conn)
if self.user_version == 5: # Upgrade to 6
LibraryDatabase.upgrade_version5(self.conn)
def close(self): def close(self):
global _lock_file global _lock_file
@ -1049,6 +1067,24 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
self.conn.execute('INSERT INTO comments(book,text) VALUES (?,?)', (id, text)) self.conn.execute('INSERT INTO comments(book,text) VALUES (?,?)', (id, text))
self.conn.commit() self.conn.commit()
def is_tag_used(self, tag):
id = self.conn.execute('SELECT id FROM tags WHERE name=?', (tag,)).fetchone()
if not id:
return False
return bool(self.conn.execute('SELECT tag FROM books_tags_link WHERE tag=?',(id[0],)).fetchone())
def delete_tag(self, tag):
id = self.conn.execute('SELECT id FROM tags WHERE name=?', (tag,)).fetchone()
if id:
id = id[0]
self.conn.execute('DELETE FROM books_tags_link WHERE tag=?', (id,))
self.conn.execute('DELETE FROM tags WHERE id=?', (id,))
self.conn.commit()
def delete_tags(self, tags):
for tag in tags:
self.delete_tag(tag)
def set_tags(self, id, tags, append=False): def set_tags(self, id, tags, append=False):
''' '''
@param tags: list of strings @param tags: list of strings