Complete rewrite of viewer bookmarks manager

Ebook-viewer: Allow re-ordering bookmarks in the bookmarks manager by
drag and drop.
This commit is contained in:
Kovid Goyal 2013-07-25 10:29:25 +05:30
parent be4dbafc9d
commit ce5821eec8
2 changed files with 71 additions and 81 deletions

View File

@ -1,15 +1,17 @@
from __future__ import with_statement #!/usr/bin/env python
# vim:fileencoding=utf-8
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2009, John Schember <john@nachtimwald.com>' __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import cPickle, os import cPickle, os
from PyQt4.Qt import (Qt, QDialog, QAbstractListModel, QVariant, from PyQt4.Qt import (
QModelIndex, QInputDialog, QLineEdit, QFileDialog, QItemSelectionModel) Qt, QDialog, QListWidgetItem, QFileDialog, QItemSelectionModel)
from calibre.gui2.viewer.bookmarkmanager_ui import Ui_BookmarkManager from calibre.gui2.viewer.bookmarkmanager_ui import Ui_BookmarkManager
from calibre.gui2 import NONE
class BookmarkManager(QDialog, Ui_BookmarkManager): class BookmarkManager(QDialog, Ui_BookmarkManager):
def __init__(self, parent, bookmarks): def __init__(self, parent, bookmarks):
@ -17,7 +19,7 @@ class BookmarkManager(QDialog, Ui_BookmarkManager):
self.setupUi(self) self.setupUi(self)
self.bookmarks = bookmarks[:] self.original_bookmarks = bookmarks
self.set_bookmarks() self.set_bookmarks()
self.button_revert.clicked.connect(lambda :self.set_bookmarks()) self.button_revert.clicked.connect(lambda :self.set_bookmarks())
@ -26,46 +28,68 @@ class BookmarkManager(QDialog, Ui_BookmarkManager):
self.button_export.clicked.connect(self.export_bookmarks) self.button_export.clicked.connect(self.export_bookmarks)
self.button_import.clicked.connect(self.import_bookmarks) self.button_import.clicked.connect(self.import_bookmarks)
self.bookmarks_list.setStyleSheet('QListView::item { padding: 0.5ex }') self.bookmarks_list.setStyleSheet('QListView::item { padding: 0.5ex }')
self.bookmarks_list.viewport().setAcceptDrops(True)
self.bookmarks_list.setDropIndicatorShown(True)
self.bookmarks_list.itemChanged.connect(self.item_changed)
self.resize(600, 500) self.resize(600, 500)
self.bookmarks_list.setFocus(Qt.OtherFocusReason)
def set_bookmarks(self, bookmarks=None): def set_bookmarks(self, bookmarks=None):
if bookmarks is None: if bookmarks is None:
bookmarks = self.bookmarks[:] bookmarks = self.original_bookmarks
self._model = BookmarkListModel(self, bookmarks) self.bookmarks_list.clear()
self.bookmarks_list.setModel(self._model) for bm in bookmarks:
if self._model.rowCount(QModelIndex()) > 0: i = QListWidgetItem(bm['title'])
self.bookmarks_list.selectionModel().select(self._model.index(0), QItemSelectionModel.SelectCurrent) i.setData(Qt.UserRole, self.bm_to_item(bm))
i.setFlags(i.flags() | Qt.ItemIsEditable)
self.bookmarks_list.addItem(i)
if len(bookmarks) > 0:
self.bookmarks_list.setCurrentItem(self.bookmarks_list.item(0), QItemSelectionModel.ClearAndSelect)
def item_changed(self, item):
self.bookmarks_list.blockSignals(True)
title = unicode(item.data(Qt.DisplayRole).toString())
if not title:
title = _('Unknown')
item.setData(Qt.DisplayRole, title)
bm = self.item_to_bm(item)
bm['title'] = title
item.setData(Qt.UserRole, self.bm_to_item(bm))
self.bookmarks_list.blockSignals(False)
def delete_bookmark(self): def delete_bookmark(self):
indexes = list(self.bookmarks_list.selectionModel().selectedIndexes()) row = self.bookmarks_list.currentRow()
if indexes: if row > -1:
self._model.remove_row(indexes[0].row()) self.bookmarks_list.takeItem(row)
def edit_bookmark(self): def edit_bookmark(self):
indexes = list(self.bookmarks_list.selectionModel().selectedIndexes()) item = self.bookmarks_list.currentItem()
if indexes: if item is not None:
title, ok = QInputDialog.getText(self, _('Edit bookmark'), _( self.bookmarks_list.editItem(item)
'New title for bookmark:'), QLineEdit.Normal, self._model.data(indexes[0], Qt.DisplayRole).toString())
title = QVariant(unicode(title).strip()) def bm_to_item(self, bm):
if ok and title: return bytearray(cPickle.dumps(bm, -1))
self._model.setData(indexes[0], title, Qt.EditRole)
def item_to_bm(self, item):
return cPickle.loads(bytes(item.data(Qt.UserRole).toPyObject()))
def get_bookmarks(self): def get_bookmarks(self):
return self._model.bookmarks l = self.bookmarks_list
return [self.item_to_bm(l.item(i)) for i in xrange(l.count())]
def export_bookmarks(self): def export_bookmarks(self):
filename = QFileDialog.getSaveFileName(self, _("Export Bookmarks"), filename = QFileDialog.getSaveFileName(self, _("Export Bookmarks"),
'%s%suntitled.pickle' % (os.getcwdu(), os.sep), '%s%suntitled.pickle' % (os.getcwdu(), os.sep),
_("Saved Bookmarks (*.pickle)")) _("Saved Bookmarks (*.pickle)"))
if filename == '': if not filename:
return return
with open(filename, 'w') as fileobj: with open(filename, 'w') as fileobj:
cPickle.dump(self._model.bookmarks, fileobj) cPickle.dump(self.get_bookmarks(), fileobj)
def import_bookmarks(self): def import_bookmarks(self):
filename = QFileDialog.getOpenFileName(self, _("Import Bookmarks"), '%s' % os.getcwdu(), _("Pickled Bookmarks (*.pickle)")) filename = QFileDialog.getOpenFileName(self, _("Import Bookmarks"), '%s' % os.getcwdu(), _("Pickled Bookmarks (*.pickle)"))
if filename == '': if not filename:
return return
imported = None imported = None
@ -83,61 +107,18 @@ class BookmarkManager(QDialog, Ui_BookmarkManager):
pass pass
if not bad: if not bad:
bookmarks = self._model.bookmarks[:] bookmarks = self.get_bookmarks()
for bm in imported: for bm in imported:
if bm not in bookmarks and bm['title'] != 'calibre_current_page_bookmark': if bm not in bookmarks and bm['title'] != 'calibre_current_page_bookmark':
bookmarks.append(bm) bookmarks.append(bm)
self.set_bookmarks(bookmarks) self.set_bookmarks(bookmarks)
class BookmarkListModel(QAbstractListModel):
def __init__(self, parent, bookmarks):
QAbstractListModel.__init__(self, parent)
self.bookmarks = bookmarks[:]
def rowCount(self, parent):
if parent and parent.isValid():
return 0
return len(self.bookmarks)
def data(self, index, role):
if role in (Qt.DisplayRole, Qt.EditRole):
ans = self.bookmarks[index.row()]['title']
return NONE if ans is None else QVariant(ans)
return NONE
def setData(self, index, value, role):
if role == Qt.EditRole:
bm = self.bookmarks[index.row()]
bm['title'] = unicode(value.toString()).strip()
self.dataChanged.emit(index, index)
return True
return False
def flags(self, index):
flags = QAbstractListModel.flags(self, index)
flags |= Qt.ItemIsEditable
return flags
def headerData(self, section, orientation, role):
if role != Qt.DisplayRole:
return NONE
if orientation == Qt.Horizontal:
return QVariant(self.headers[section])
else:
return QVariant(section+1)
def remove_row(self, row):
self.beginRemoveRows(QModelIndex(), row, row)
del self.bookmarks[row]
self.endRemoveRows()
if __name__ == '__main__': if __name__ == '__main__':
from PyQt4.Qt import QApplication from PyQt4.Qt import QApplication
app = QApplication([]) app = QApplication([])
d = BookmarkManager(None, [{'title':'Bookmark #%d' % i} for i in range(1, 50)]) d = BookmarkManager(None, [{'title':'Bookmark #%d' % i, 'data':b'xxxxx'} for i in range(1, 5)])
d.exec_() d.exec_()
import pprint
pprint.pprint(d.get_bookmarks())

View File

@ -14,13 +14,6 @@
<string>Bookmark Manager</string> <string>Bookmark Manager</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
@ -85,8 +78,24 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QListView" name="bookmarks_list"> <widget class="QListWidget" name="bookmarks_list">
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors"> <property name="alternatingRowColors">
<bool>true</bool> <bool>true</bool>
</property> </property>