Cover grid: Fix dragging the mouse while holding shift to extend the selection not working well. Fixes #2054617 [Multiple book selection in cover grid using mouse and shift key](https://bugs.launchpad.net/calibre/+bug/2054617)

This commit is contained in:
Kovid Goyal 2024-02-28 16:57:57 +05:30
parent e1238ea3ee
commit 275cfd4875
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -210,15 +210,18 @@ def drag_data(self):
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
if not self.drag_allowed:
return
if self.drag_start_pos is None:
return qt_item_view_base_class(self).mouseMoveEvent(self, event)
if self.event_has_mods(): if self.event_has_mods():
self.drag_start_pos = None self.drag_start_pos = None
if not self.drag_allowed:
if hasattr(self, 'handle_mouse_move_event'):
self.handle_mouse_move_event(event)
return
if self.drag_start_pos is None:
if hasattr(self, 'handle_mouse_move_event'):
self.handle_mouse_move_event(event)
else:
qt_item_view_base_class(self).mouseMoveEvent(self, event)
return return
if not (event.buttons() & Qt.MouseButton.LeftButton) or \ if not (event.buttons() & Qt.MouseButton.LeftButton) or \
(event.pos() - self.drag_start_pos).manhattanLength() \ (event.pos() - self.drag_start_pos).manhattanLength() \
< QApplication.startDragDistance(): < QApplication.startDragDistance():
@ -727,6 +730,7 @@ class GridView(QListView):
def __init__(self, parent): def __init__(self, parent):
QListView.__init__(self, parent) QListView.__init__(self, parent)
self.shift_click_start_data = None
self.dbref = lambda: None self.dbref = lambda: None
self._ncols = None self._ncols = None
self.gesture_manager = GestureManager(self) self.gesture_manager = GestureManager(self)
@ -1160,21 +1164,54 @@ class GridView(QListView):
def restore_hpos(self, hpos): def restore_hpos(self, hpos):
pass pass
def handle_mouse_move_event(self, ev):
# handle shift drag to extend selections
if not QApplication.keyboardModifiers() & Qt.KeyboardModifier.ShiftModifier:
return super().mouseMoveEvent(ev)
index = self.indexAt(ev.pos())
if not index.isValid() or not self.shift_click_start_data:
return
m = self.model()
ci = m.index(self.shift_click_start_data[0], 0)
if not ci.isValid():
return
sm = self.selectionModel()
sm.setCurrentIndex(index, QItemSelectionModel.SelectionFlag.NoUpdate)
if not sm.hasSelection():
sm.select(index, QItemSelectionModel.SelectionFlag.ClearAndSelect)
return True
cr = ci.row()
tgt = index.row()
if cr == tgt:
sm.select(index, QItemSelectionModel.SelectionFlag.Select)
return
if cr < tgt:
# mouse is moved after the start pos
top = min(self.shift_click_start_data[1], cr)
bottom = tgt
else:
top = tgt
bottom = max(self.shift_click_start_data[2], cr)
sm.select(QItemSelection(m.index(top, 0), m.index(bottom, 0)), QItemSelectionModel.SelectionFlag.ClearAndSelect)
def handle_mouse_press_event(self, ev): def handle_mouse_press_event(self, ev):
if QApplication.keyboardModifiers() & Qt.KeyboardModifier.ShiftModifier: # Shift-Click in QListView is broken. It selects extra items in
# Shift-Click in QListView is broken. It selects extra items in # various circumstances, for example, click on some item in the
# various circumstances, for example, click on some item in the # middle of a row then click on an item in the next row, all items
# middle of a row then click on an item in the next row, all items # in the first row will be selected instead of only items after the
# in the first row will be selected instead of only items after the # middle item.
# middle item. if not QApplication.keyboardModifiers() & Qt.KeyboardModifier.ShiftModifier:
index = self.indexAt(ev.pos()) return super().mousePressEvent(ev)
if not index.isValid(): self.shift_click_start_data = None
return index = self.indexAt(ev.pos())
ci = self.currentIndex() if not index.isValid():
sm = self.selectionModel() return
sm.setCurrentIndex(index, QItemSelectionModel.SelectionFlag.NoUpdate) sm = self.selectionModel()
ci = self.currentIndex()
try:
if not ci.isValid(): if not ci.isValid():
return return
sm.setCurrentIndex(index, QItemSelectionModel.SelectionFlag.NoUpdate)
if not sm.hasSelection(): if not sm.hasSelection():
sm.select(index, QItemSelectionModel.SelectionFlag.ClearAndSelect) sm.select(index, QItemSelectionModel.SelectionFlag.ClearAndSelect)
return return
@ -1183,8 +1220,16 @@ class GridView(QListView):
top = self.model().index(min(cr, tgt), 0) top = self.model().index(min(cr, tgt), 0)
bottom = self.model().index(max(cr, tgt), 0) bottom = self.model().index(max(cr, tgt), 0)
sm.select(QItemSelection(top, bottom), QItemSelectionModel.SelectionFlag.Select) sm.select(QItemSelection(top, bottom), QItemSelectionModel.SelectionFlag.Select)
else: finally:
return QListView.mousePressEvent(self, ev) min_row = self.model().rowCount(QModelIndex())
max_row = -1
for idx in sm.selectedIndexes():
r = idx.row()
if r < min_row:
min_row = r
elif r > max_row:
max_row = r
self.shift_click_start_data = index.row(), min_row, max_row
def indices_for_merge(self, resolved=True): def indices_for_merge(self, resolved=True):
return self.selectionModel().selectedIndexes() return self.selectionModel().selectedIndexes()