Edit book: File browser: Allow using keyboard shortcuts to re-order the spine

This commit is contained in:
Kovid Goyal 2022-12-17 15:01:10 +05:30
parent 6e5a424640
commit c24f59151c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 52 additions and 6 deletions

View File

@ -133,11 +133,14 @@ Changing text file order
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
You can re-arrange the order in which text (HTML) files are opened when reading You can re-arrange the order in which text (HTML) files are opened when reading
the book by simply dragging and dropping them in the Files browser. For the the book by simply dragging and dropping them in the Files browser or clicking
technically inclined, this is called re-ordering the book spine. Note that you on the file to move and then pressing the :kbd:`Ctrl+Shift` modifiers with the
have to drop the items *between* other items, not on top of them, this can be a :kbd:`Up`, :kbd:`Down`, :kbd:`Home` or :kbd:`End` keys. For the technically
little fiddly until you get used to it. Dropping on top of another file will inclined, this is called re-ordering the book spine.
cause the files to be merged.
Note that you have to drop the items *between* other items, not on top of them,
this can be a little fiddly until you get used to it. Dropping on top of
another file will cause the files to be merged.
Marking the cover Marking the cover
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -374,6 +374,9 @@ class FileList(QTreeWidget, OpenWithHandler):
return return
new_names = new_names[:insertion_point] + names + new_names[insertion_point:] new_names = new_names[:insertion_point] + names + new_names[insertion_point:]
order = [[name, linear_map[name]] for name in new_names] order = [[name, linear_map[name]] for name in new_names]
self.request_reorder(order)
def request_reorder(self, order):
# Ensure that all non-linear items are at the end, by making any non-linear # Ensure that all non-linear items are at the end, by making any non-linear
# items not at the end, linear # items not at the end, linear
for i, (name, linear) in tuple(enumerate(order)): for i, (name, linear) in tuple(enumerate(order)):
@ -797,9 +800,20 @@ class FileList(QTreeWidget, OpenWithHandler):
self.mark_requested.emit(name, 'nav') self.mark_requested.emit(name, 'nav')
def keyPressEvent(self, ev): def keyPressEvent(self, ev):
if ev.key() in (Qt.Key.Key_Delete, Qt.Key.Key_Backspace): k = ev.key()
mods = ev.modifiers() & (
Qt.KeyboardModifier.ShiftModifier | Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.MetaModifier)
if k in (Qt.Key.Key_Delete, Qt.Key.Key_Backspace):
ev.accept() ev.accept()
self.request_delete() self.request_delete()
elif mods == (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier):
m = self.categories['text'].childCount()
amt = {Qt.Key.Key_Up: -1, Qt.Key.Key_Down: 1, Qt.Key.Key_Home: -m, Qt.Key.Key_End: m}.get(k, None)
if amt is not None:
ev.accept()
self.move_selected_text_items(amt)
else:
return QTreeWidget.keyPressEvent(self, ev)
else: else:
return QTreeWidget.keyPressEvent(self, ev) return QTreeWidget.keyPressEvent(self, ev)
@ -861,6 +875,35 @@ class FileList(QTreeWidget, OpenWithHandler):
ans.discard('') ans.discard('')
return ans return ans
def move_selected_text_items(self, amt: int) -> bool:
parent = self.categories['text']
children = tuple(parent.child(i) for i in range(parent.childCount()))
selected_names = tuple(c.data(0, NAME_ROLE) for c in children if c.isSelected())
if not selected_names or amt == 0:
return False
current_order = tuple(c.data(0, NAME_ROLE) for c in children)
linear_map = {c.data(0, NAME_ROLE):c.data(0, LINEAR_ROLE) for c in children}
order_map = {name: i for i, name in enumerate(current_order)}
new_order = list(current_order)
changed = False
items = reversed(selected_names) if amt > 0 else selected_names
if amt < 0:
items = selected_names
delta = max(amt, -order_map[selected_names[0]])
else:
items = reversed(selected_names)
delta = min(amt, len(children) - 1 - order_map[selected_names[-1]])
for name in items:
i = order_map[name]
new_i = min(max(0, i + delta), len(current_order) - 1)
if new_i != i:
changed = True
del new_order[i]
new_order.insert(new_i, name)
if changed:
self.request_reorder([[n, linear_map[n]] for n in new_order])
return changed
def copy_selected_files(self): def copy_selected_files(self):
self.initiate_file_copy.emit(self.selected_names) self.initiate_file_copy.emit(self.selected_names)