diff --git a/src/libprs500/gui2/Makefile b/src/libprs500/gui2/Makefile
index 25241d654d..1ef49a19be 100644
--- a/src/libprs500/gui2/Makefile
+++ b/src/libprs500/gui2/Makefile
@@ -1,4 +1,4 @@
-UI = main_ui.py dialogs/metadata_single_ui.py
+UI = main_ui.py dialogs/metadata_single_ui.py dialogs/metadata_bulk_ui.py
RC = images_rc.pyc
%_ui.py : %.ui
diff --git a/src/libprs500/gui2/dialogs/metadata_bulk.py b/src/libprs500/gui2/dialogs/metadata_bulk.py
new file mode 100644
index 0000000000..923670cb16
--- /dev/null
+++ b/src/libprs500/gui2/dialogs/metadata_bulk.py
@@ -0,0 +1,73 @@
+## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
+## 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; either version 2 of the License, or
+## (at your option) any later version.
+##
+## 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.,
+## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+'''Dialog to edit metadata in bulk'''
+
+from PyQt4.QtCore import SIGNAL, QObject
+
+from libprs500.gui2 import qstring_to_unicode
+from libprs500.gui2.dialogs import ModalDialog
+from libprs500.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
+
+class MetadataBulkDialog(Ui_MetadataBulkDialog, ModalDialog):
+ def __init__(self, window, rows, db):
+ Ui_MetadataBulkDialog.__init__(self)
+ ModalDialog.__init__(self, window)
+ self.setupUi(self.dialog)
+ self.db = db
+ self.ids = [ db.id(r) for r in rows]
+ self.write_series = False
+ self.write_rating = False
+ self.changed = False
+ QObject.connect(self.button_box, SIGNAL("accepted()"), self.sync)
+ QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.series_changed)
+ QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.series_changed)
+ QObject.connect(self.rating, SIGNAL('valueChanged(int)'), self.rating_changed)
+
+ all_series = self.db.all_series()
+
+ for i in all_series:
+ id, name = i
+ self.series.addItem(name)
+
+
+
+ self.dialog.exec_()
+
+
+ def sync(self):
+ for id in self.ids:
+ au = qstring_to_unicode(self.authors.text())
+ if au:
+ au = au.split(',')
+ self.db.set_authors(id, au)
+ if self.write_rating:
+ self.db.set_rating(id, 2*self.rating.value())
+ pub = qstring_to_unicode(self.publisher.text())
+ if pub:
+ self.db.set_publisher(id, pub)
+ tags = qstring_to_unicode(self.tags.text())
+ if tags:
+ tags = tags.split(tags)
+ self.db.set_tags(id, tags, append=True)
+ if self.write_series:
+ self.db.set_series(id, qstring_to_unicode(self.series.currentText()))
+ self.changed = True
+
+ def series_changed(self):
+ self.write_series = True
+
+ def rating_changed(self):
+ self.write_rating = True
\ No newline at end of file
diff --git a/src/libprs500/gui2/dialogs/metadata_bulk.ui b/src/libprs500/gui2/dialogs/metadata_bulk.ui
new file mode 100644
index 0000000000..2fb614c2bf
--- /dev/null
+++ b/src/libprs500/gui2/dialogs/metadata_bulk.ui
@@ -0,0 +1,248 @@
+
+ MetadataBulkDialog
+
+
+ Qt::ApplicationModal
+
+
+
+ 0
+ 0
+ 461
+ 342
+
+
+
+ Edit Meta information
+
+
+ :/images/edit_input.svg
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+ 6
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Meta information
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ Rating of this book. 0-5 stars
+
+
+ Rating of this book. 0-5 stars
+
+
+ QAbstractSpinBox::PlusMinus
+
+
+ stars
+
+
+ 5
+
+
+
+ -
+
+
+ &Rating:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Change the publisher of this book
+
+
+
+ -
+
+
+ &Publisher:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ publisher
+
+
+
+ -
+
+
+ Add Ta&gs:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ tags
+
+
+
+ -
+
+
+ Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.
+
+
+
+ -
+
+
+ Change the author(s) of this book. Multiple authors should be separated by a comma
+
+
+
+ -
+
+
+ &Author(s):
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ authors
+
+
+
+ -
+
+
+ List of known series. You can add new series.
+
+
+ List of known series. You can add new series.
+
+
+ true
+
+
+ QComboBox::InsertAlphabetically
+
+
+ QComboBox::AdjustToContents
+
+
+
+ -
+
+
+ &Series:
+
+
+ Qt::PlainText
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ series
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+
+
+ button_box
+ accepted()
+ MetadataBulkDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ button_box
+ rejected()
+ MetadataBulkDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/libprs500/gui2/dialogs/metadata_single.py b/src/libprs500/gui2/dialogs/metadata_single.py
index 2516fbb1e3..66ee796176 100644
--- a/src/libprs500/gui2/dialogs/metadata_single.py
+++ b/src/libprs500/gui2/dialogs/metadata_single.py
@@ -19,8 +19,7 @@ add/remove formats
import os
from PyQt4.QtCore import SIGNAL
-from PyQt4.Qt import QObject, QPixmap, QListWidgetItem, QErrorMessage, \
- QVariant, QSettings, QFileDialog
+from PyQt4.Qt import QObject, QPixmap, QListWidgetItem, QErrorMessage
from libprs500.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
@@ -171,8 +170,6 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, ModalDialog):
if qstring_to_unicode(self.series.currentText()):
self.enable_series_index()
- QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.enable_series_index)
- QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index)
all_series = self.db.all_series()
series_id = self.db.series_id(row)
@@ -183,10 +180,14 @@ class MetadataSingleDialog(Ui_MetadataSingleDialog, ModalDialog):
idx = c
self.series.addItem(name)
c += 1
+
+ self.series.lineEdit().setText('')
if idx is not None:
self.series.setCurrentIndex(idx)
self.series_index.setValue(self.db.series_index(row))
+ QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.enable_series_index)
+ QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index)
self.dialog.exec_()
diff --git a/src/libprs500/gui2/dialogs/metadata_single.ui b/src/libprs500/gui2/dialogs/metadata_single.ui
index f3f0cee0c5..13dbda62b8 100644
--- a/src/libprs500/gui2/dialogs/metadata_single.ui
+++ b/src/libprs500/gui2/dialogs/metadata_single.ui
@@ -1,6 +1,9 @@
MetadataSingleDialog
+
+ Qt::ApplicationModal
+
0
@@ -10,7 +13,7 @@
- libprs500 - Edit Meta Information
+ Edit Meta Information
:/images/edit_input.svg
diff --git a/src/libprs500/gui2/main.py b/src/libprs500/gui2/main.py
index 2efb32ddde..5b81ce3cf3 100644
--- a/src/libprs500/gui2/main.py
+++ b/src/libprs500/gui2/main.py
@@ -31,6 +31,7 @@ from libprs500.gui2.device import DeviceDetector, DeviceManager
from libprs500.gui2.status import StatusBar
from libprs500.gui2.jobs import JobManager, JobException
from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog
+from libprs500.gui2.dialogs.metadata_bulk import MetadataBulkDialog
class Main(QObject, Ui_MainWindow):
@@ -73,14 +74,23 @@ class Main(QObject, Ui_MainWindow):
sm.addAction(QIcon(':/images/reader.svg'), 'Send to main memory')
sm.addAction(QIcon(':/images/sd.svg'), 'Send to storage card')
self.sync_menu = sm # Needed
+ md = QMenu()
+ md.addAction('Edit metadata individually')
+ md.addAction('Edit metadata in bulk')
+ self.metadata_menu = md
QObject.connect(self.action_add, SIGNAL("triggered(bool)"), self.add_books)
QObject.connect(self.action_del, SIGNAL("triggered(bool)"), self.delete_books)
QObject.connect(self.action_edit, SIGNAL("triggered(bool)"), self.edit_metadata)
+ QObject.connect(md.actions()[0], SIGNAL('triggered(bool)'), self.edit_metadata)
+ QObject.connect(md.actions()[1], SIGNAL('triggered(bool)'), self.edit_bulk_metadata)
QObject.connect(self.action_sync, SIGNAL("triggered(bool)"), self.sync_to_main_memory)
QObject.connect(sm.actions()[0], SIGNAL('triggered(bool)'), self.sync_to_main_memory)
QObject.connect(sm.actions()[1], SIGNAL('triggered(bool)'), self.sync_to_card)
+
self.action_sync.setMenu(sm)
- self.tool_bar.insertAction(self.action_edit, self.action_sync)
+ self.action_edit.setMenu(md)
+ self.tool_bar.addAction(self.action_sync)
+ self.tool_bar.addAction(self.action_edit)
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
####################### Library view ########################
@@ -312,6 +322,8 @@ class Main(QObject, Ui_MainWindow):
'''
rows = self.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
+ d = error_dialog(self.window, 'Cannot edit metadata', 'No books selected')
+ d.exec_()
return
changed = False
for row in rows:
@@ -323,6 +335,19 @@ class Main(QObject, Ui_MainWindow):
self.library_view.model().resort()
self.library_view.model().research()
+ def edit_bulk_metadata(self, checked):
+ '''
+ Edit metadata of selected books in library in bulk.
+ '''
+ rows = [r.row() for r in self.library_view.selectionModel().selectedRows()]
+ if not rows or len(rows) == 0:
+ d = error_dialog(self.window, 'Cannot edit metadata', 'No books selected')
+ d.exec_()
+ return
+ if MetadataBulkDialog(self.window, rows, self.library_view.model().db).changed:
+ self.library_view.model().resort()
+ self.library_view.model().research()
+
############################################################################
############################# Syncing to device#############################
diff --git a/src/libprs500/gui2/main.ui b/src/libprs500/gui2/main.ui
index 56b4fc8f4e..b683153466 100644
--- a/src/libprs500/gui2/main.ui
+++ b/src/libprs500/gui2/main.ui
@@ -319,7 +319,6 @@
-
diff --git a/src/libprs500/library/database.py b/src/libprs500/library/database.py
index cc12d3788e..ec9de2e581 100644
--- a/src/libprs500/library/database.py
+++ b/src/libprs500/library/database.py
@@ -785,11 +785,13 @@ class LibraryDatabase(object):
self.conn.execute('INSERT INTO comments(book,text) VALUES (?,?)', (id, text))
self.conn.commit()
- def set_tags(self, id, tags):
+ def set_tags(self, id, tags, append=False):
'''
@param tags: list of strings
+ @param append: If True existing tags are not removed
'''
- self.conn.execute('DELETE FROM books_tags_link WHERE book=?', (id,))
+ if not append:
+ self.conn.execute('DELETE FROM books_tags_link WHERE book=?', (id,))
tag = set(tags)
for tag in tags:
t = self.conn.execute('SELECT id from tags WHERE name=?', (tag,)).fetchone()
@@ -797,7 +799,9 @@ class LibraryDatabase(object):
tid = t[0]
else:
tid = self.conn.execute('INSERT INTO tags(name) VALUES(?)', (tag,)).lastrowid
- self.conn.execute('INSERT INTO books_tags_link(book, tag) VALUES (?,?)',
+ if (append and not self.conn.execute('SELECT book FROM books_tags_link WHERE book=? AND tag=?',
+ (id, tid)).fetchone()) or not append:
+ self.conn.execute('INSERT INTO books_tags_link(book, tag) VALUES (?,?)',
(id, tid))
self.conn.commit()