mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Drag 'n drop re-ordering of spine items
This commit is contained in:
parent
26c1fd0689
commit
7f2a1f99da
@ -355,6 +355,28 @@ class Container(object): # {{{
|
|||||||
for name in nixed:
|
for name in nixed:
|
||||||
self.remove_item(name)
|
self.remove_item(name)
|
||||||
|
|
||||||
|
def set_spine(self, spine_items):
|
||||||
|
''' Set the spine to be spine_items where spine_items is an iterable of
|
||||||
|
the form (name, linear). Will raise an error if one of the names is not
|
||||||
|
present in the manifest. '''
|
||||||
|
imap = self.manifest_id_map
|
||||||
|
imap = {name:item_id for item_id, name in imap.iteritems()}
|
||||||
|
items = [item for item, name, linear in self.spine_iter]
|
||||||
|
tail, last_tail = (items[0].tail, items[-1].tail) if items else ('\n ', '\n ')
|
||||||
|
map(self.remove_from_xml, items)
|
||||||
|
spine = self.opf_xpath('//opf:spine')[0]
|
||||||
|
spine.text = tail
|
||||||
|
for name, linear in spine_items:
|
||||||
|
i = spine.makeelement('{%s}itemref' % OPF_NAMESPACES['opf'], nsmap={'opf':OPF_NAMESPACES['opf']})
|
||||||
|
i.tail = tail
|
||||||
|
i.set('idref', imap[name])
|
||||||
|
spine.append(i)
|
||||||
|
if not linear:
|
||||||
|
i.set('linear', 'no')
|
||||||
|
if len(spine) > 0:
|
||||||
|
spine[-1].tail = last_tail
|
||||||
|
self.dirty(self.opf_name)
|
||||||
|
|
||||||
def remove_item(self, name):
|
def remove_item(self, name):
|
||||||
'''
|
'''
|
||||||
Remove the item identified by name from this container. This removes all
|
Remove the item identified by name from this container. This removes all
|
||||||
|
@ -35,6 +35,7 @@ class Boss(QObject):
|
|||||||
def __call__(self, gui):
|
def __call__(self, gui):
|
||||||
self.gui = gui
|
self.gui = gui
|
||||||
gui.file_list.delete_requested.connect(self.delete_requested)
|
gui.file_list.delete_requested.connect(self.delete_requested)
|
||||||
|
gui.file_list.reorder_spine.connect(self.reorder_spine)
|
||||||
|
|
||||||
def mkdtemp(self):
|
def mkdtemp(self):
|
||||||
self.container_count += 1
|
self.container_count += 1
|
||||||
@ -130,6 +131,16 @@ class Boss(QObject):
|
|||||||
self.gui.file_list.delete_done(spine_items, other_items)
|
self.gui.file_list.delete_done(spine_items, other_items)
|
||||||
# TODO: Update other GUI elements
|
# TODO: Update other GUI elements
|
||||||
|
|
||||||
|
def reorder_spine(self, items):
|
||||||
|
# TODO: If content.opf is dirty in an editor, abort, calling
|
||||||
|
# file_list.build(current_container) to undo drag and drop
|
||||||
|
self.add_savepoint(_('Re-order text'))
|
||||||
|
c = current_container()
|
||||||
|
c.set_spine(items)
|
||||||
|
self.gui.action_save.setEnabled(True)
|
||||||
|
self.gui.file_list.build(current_container()) # needed as the linear flag may have changed on some items
|
||||||
|
# TODO: If content.opf is open in an editor, reload it
|
||||||
|
|
||||||
def save_book(self):
|
def save_book(self):
|
||||||
self.gui.action_save.setEnabled(False)
|
self.gui.action_save.setEnabled(False)
|
||||||
tdir = tempfile.mkdtemp(prefix='save-%05d-' % self.container_count, dir=self.tdir)
|
tdir = tempfile.mkdtemp(prefix='save-%05d-' % self.container_count, dir=self.tdir)
|
||||||
|
@ -22,6 +22,7 @@ from calibre.utils.icu import sort_key
|
|||||||
TOP_ICON_SIZE = 24
|
TOP_ICON_SIZE = 24
|
||||||
NAME_ROLE = Qt.UserRole
|
NAME_ROLE = Qt.UserRole
|
||||||
CATEGORY_ROLE = NAME_ROLE + 1
|
CATEGORY_ROLE = NAME_ROLE + 1
|
||||||
|
LINEAR_ROLE = CATEGORY_ROLE + 1
|
||||||
NBSP = '\xa0'
|
NBSP = '\xa0'
|
||||||
|
|
||||||
class ItemDelegate(QStyledItemDelegate): # {{{
|
class ItemDelegate(QStyledItemDelegate): # {{{
|
||||||
@ -56,6 +57,7 @@ class ItemDelegate(QStyledItemDelegate): # {{{
|
|||||||
class FileList(QTreeWidget):
|
class FileList(QTreeWidget):
|
||||||
|
|
||||||
delete_requested = pyqtSignal(object, object)
|
delete_requested = pyqtSignal(object, object)
|
||||||
|
reorder_spine = pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QTreeWidget.__init__(self, parent)
|
QTreeWidget.__init__(self, parent)
|
||||||
@ -211,6 +213,7 @@ class FileList(QTreeWidget):
|
|||||||
item.setStatusTip(0, _('Full path: ') + name)
|
item.setStatusTip(0, _('Full path: ') + name)
|
||||||
item.setData(0, NAME_ROLE, name)
|
item.setData(0, NAME_ROLE, name)
|
||||||
item.setData(0, CATEGORY_ROLE, category)
|
item.setData(0, CATEGORY_ROLE, category)
|
||||||
|
item.setData(0, LINEAR_ROLE, bool(linear))
|
||||||
set_display_name(name, item)
|
set_display_name(name, item)
|
||||||
# TODO: Add appropriate tooltips based on the emblems
|
# TODO: Add appropriate tooltips based on the emblems
|
||||||
emblems = []
|
emblems = []
|
||||||
@ -294,11 +297,22 @@ class FileList(QTreeWidget):
|
|||||||
super(FileList, self).dropEvent(event)
|
super(FileList, self).dropEvent(event)
|
||||||
current_order = {text.child(i):i for i in xrange(text.childCount())}
|
current_order = {text.child(i):i for i in xrange(text.childCount())}
|
||||||
if current_order != pre_drop_order:
|
if current_order != pre_drop_order:
|
||||||
pass # TODO: Implement this
|
order = []
|
||||||
|
for child in (text.child(i) for i in xrange(text.childCount())):
|
||||||
|
name = unicode(child.data(0, NAME_ROLE).toString())
|
||||||
|
linear = child.data(0, LINEAR_ROLE).toBool()
|
||||||
|
order.append([name, linear])
|
||||||
|
# Ensure that all non-linear items are at the end, any non-linear
|
||||||
|
# items not at the end will be made linear
|
||||||
|
for i, (name, linear) in tuple(enumerate(order)):
|
||||||
|
if not linear and i < len(order) - 1 and order[i+1][1]:
|
||||||
|
order[i][1] = True
|
||||||
|
self.reorder_spine.emit(order)
|
||||||
|
|
||||||
class FileListWidget(QWidget):
|
class FileListWidget(QWidget):
|
||||||
|
|
||||||
delete_requested = pyqtSignal(object, object)
|
delete_requested = pyqtSignal(object, object)
|
||||||
|
reorder_spine = pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
@ -306,7 +320,7 @@ class FileListWidget(QWidget):
|
|||||||
self.file_list = FileList(self)
|
self.file_list = FileList(self)
|
||||||
self.layout().addWidget(self.file_list)
|
self.layout().addWidget(self.file_list)
|
||||||
self.layout().setContentsMargins(0, 0, 0, 0)
|
self.layout().setContentsMargins(0, 0, 0, 0)
|
||||||
for x in ('delete_requested',):
|
for x in ('delete_requested', 'reorder_spine'):
|
||||||
getattr(self.file_list, x).connect(getattr(self, x))
|
getattr(self.file_list, x).connect(getattr(self, x))
|
||||||
for x in ('delete_done',):
|
for x in ('delete_done',):
|
||||||
setattr(self, x, getattr(self.file_list, x))
|
setattr(self, x, getattr(self.file_list, x))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user