mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make drag & drop work again in the tag browser. Fix problem w/Qt near the end of the list.
This commit is contained in:
parent
ab16d1c0a8
commit
7dfa9897d9
@ -335,7 +335,6 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
node.is_gst = is_gst
|
node.is_gst = is_gst
|
||||||
if not is_gst:
|
if not is_gst:
|
||||||
node.tag.is_hierarchical = '5state'
|
node.tag.is_hierarchical = '5state'
|
||||||
if not is_gst:
|
|
||||||
tree_root[p] = {}
|
tree_root[p] = {}
|
||||||
tree_root = tree_root[p]
|
tree_root = tree_root[p]
|
||||||
else:
|
else:
|
||||||
@ -519,7 +518,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
# category display order is important here. The following works
|
# category display order is important here. The following works
|
||||||
# only if all the non-user categories are displayed before the
|
# only if all the non-user categories are displayed before the
|
||||||
# user categories
|
# user categories
|
||||||
if category_is_hierarchical:
|
if category_is_hierarchical or tag.is_hierarchical:
|
||||||
components = get_name_components(tag.original_name)
|
components = get_name_components(tag.original_name)
|
||||||
else:
|
else:
|
||||||
components = [tag.original_name]
|
components = [tag.original_name]
|
||||||
@ -581,6 +580,14 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
return [(t.tag.id, t.tag.original_name, t.tag.count)
|
return [(t.tag.id, t.tag.original_name, t.tag.count)
|
||||||
for t in cat.child_tags() if t.tag.count > 0]
|
for t in cat.child_tags() if t.tag.count > 0]
|
||||||
|
|
||||||
|
def is_in_user_category(self, index):
|
||||||
|
if not index.isValid():
|
||||||
|
return False
|
||||||
|
p = self.get_node(index)
|
||||||
|
while p.type != TagTreeItem.CATEGORY:
|
||||||
|
p = p.parent
|
||||||
|
return p.tag.category.startswith('@')
|
||||||
|
|
||||||
# Drag'n Drop {{{
|
# Drag'n Drop {{{
|
||||||
def mimeTypes(self):
|
def mimeTypes(self):
|
||||||
return ["application/calibre+from_library",
|
return ["application/calibre+from_library",
|
||||||
@ -646,13 +653,13 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
action is Qt.CopyAction or Qt.MoveAction
|
action is Qt.CopyAction or Qt.MoveAction
|
||||||
'''
|
'''
|
||||||
def process_source_node(user_cats, src_parent, src_parent_is_gst,
|
def process_source_node(user_cats, src_parent, src_parent_is_gst,
|
||||||
is_uc, dest_key, node):
|
is_uc, dest_key, idx):
|
||||||
'''
|
'''
|
||||||
Copy/move an item and all its children to the destination
|
Copy/move an item and all its children to the destination
|
||||||
'''
|
'''
|
||||||
copied = False
|
copied = False
|
||||||
src_name = node.tag.original_name
|
src_name = idx.tag.original_name
|
||||||
src_cat = node.tag.category
|
src_cat = idx.tag.category
|
||||||
# delete the item if the source is a user category and action is move
|
# delete the item if the source is a user category and action is move
|
||||||
if is_uc and not src_parent_is_gst and src_parent in user_cats and \
|
if is_uc and not src_parent_is_gst and src_parent in user_cats and \
|
||||||
action == Qt.MoveAction:
|
action == Qt.MoveAction:
|
||||||
@ -675,7 +682,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
if add_it:
|
if add_it:
|
||||||
user_cats[dest_key].append([src_name, src_cat, 0])
|
user_cats[dest_key].append([src_name, src_cat, 0])
|
||||||
|
|
||||||
for c in node.children:
|
for c in idx.children:
|
||||||
copied = process_source_node(user_cats, src_parent, src_parent_is_gst,
|
copied = process_source_node(user_cats, src_parent, src_parent_is_gst,
|
||||||
is_uc, dest_key, c)
|
is_uc, dest_key, c)
|
||||||
return copied
|
return copied
|
||||||
@ -696,11 +703,11 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
if dest_key not in user_cats:
|
if dest_key not in user_cats:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
node = self.index_for_path(path)
|
idx = self.index_for_path(path)
|
||||||
if node:
|
if idx.isValid():
|
||||||
process_source_node(user_cats, src_parent, src_parent_is_gst,
|
process_source_node(user_cats, src_parent, src_parent_is_gst,
|
||||||
is_uc, dest_key,
|
is_uc, dest_key,
|
||||||
self.get_node(node))
|
self.get_node(idx))
|
||||||
|
|
||||||
self.db.prefs.set('user_categories', user_cats)
|
self.db.prefs.set('user_categories', user_cats)
|
||||||
self.refresh_required.emit()
|
self.refresh_required.emit()
|
||||||
@ -1139,6 +1146,8 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
return QModelIndex()
|
return QModelIndex()
|
||||||
|
|
||||||
ans = self.createIndex(parent_item.row(), 0, parent_item)
|
ans = self.createIndex(parent_item.row(), 0, parent_item)
|
||||||
|
if not ans.isValid():
|
||||||
|
return QModelIndex()
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def rowCount(self, parent):
|
def rowCount(self, parent):
|
||||||
|
@ -12,7 +12,8 @@ from functools import partial
|
|||||||
from itertools import izip
|
from itertools import izip
|
||||||
|
|
||||||
from PyQt4.Qt import (QStyledItemDelegate, Qt, QTreeView, pyqtSignal, QSize,
|
from PyQt4.Qt import (QStyledItemDelegate, Qt, QTreeView, pyqtSignal, QSize,
|
||||||
QIcon, QApplication, QMenu, QPoint, QModelIndex, QToolTip, QCursor)
|
QIcon, QApplication, QMenu, QPoint, QModelIndex, QToolTip, QCursor,
|
||||||
|
QDrag)
|
||||||
|
|
||||||
from calibre.gui2.tag_browser.model import (TagTreeItem, TAG_SEARCH_STATES,
|
from calibre.gui2.tag_browser.model import (TagTreeItem, TAG_SEARCH_STATES,
|
||||||
TagsModel)
|
TagsModel)
|
||||||
@ -101,6 +102,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.setDragEnabled(True)
|
self.setDragEnabled(True)
|
||||||
self.setDragDropMode(self.DragDrop)
|
self.setDragDropMode(self.DragDrop)
|
||||||
self.setDropIndicatorShown(True)
|
self.setDropIndicatorShown(True)
|
||||||
|
self.in_drag_drop = False
|
||||||
self.setAutoExpandDelay(500)
|
self.setAutoExpandDelay(500)
|
||||||
self.pane_is_visible = False
|
self.pane_is_visible = False
|
||||||
self.search_icon = QIcon(I('search.png'))
|
self.search_icon = QIcon(I('search.png'))
|
||||||
@ -232,10 +234,35 @@ class TagsView(QTreeView): # {{{
|
|||||||
s = s if s else None
|
s = s if s else None
|
||||||
self._model.set_search_restriction(s)
|
self._model.set_search_restriction(s)
|
||||||
|
|
||||||
|
def mouseMoveEvent(self, event):
|
||||||
|
dex = self.indexAt(event.pos())
|
||||||
|
if self.in_drag_drop or not dex.isValid():
|
||||||
|
QTreeView.mouseMoveEvent(self, event)
|
||||||
|
return
|
||||||
|
# Must deal with odd case where the node being dragged is 'virtual',
|
||||||
|
# created to form a hierarchy. We can't really drag this node, but in
|
||||||
|
# addition we can't allow drag recognition to notice going over some
|
||||||
|
# other node and grabbing that one. So we set in_drag_drop to prevent
|
||||||
|
# this from happening, turning it off when the user lifts the button.
|
||||||
|
self.in_drag_drop = True
|
||||||
|
if not self._model.flags(dex) & Qt.ItemIsDragEnabled:
|
||||||
|
QTreeView.mouseMoveEvent(self, event)
|
||||||
|
return
|
||||||
|
md = self._model.mimeData([dex])
|
||||||
|
pixmap = dex.data(Qt.DecorationRole).toPyObject().pixmap(25, 25)
|
||||||
|
drag = QDrag(self)
|
||||||
|
drag.setPixmap(pixmap)
|
||||||
|
drag.setMimeData(md)
|
||||||
|
if self._model.is_in_user_category(dex):
|
||||||
|
drag.exec_(Qt.CopyAction|Qt.MoveAction, Qt.CopyAction)
|
||||||
|
else:
|
||||||
|
drag.exec_(Qt.CopyAction)
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
def mouseReleaseEvent(self, event):
|
||||||
# Swallow everything except leftButton so context menus work correctly
|
# Swallow everything except leftButton so context menus work correctly
|
||||||
if event.button() == Qt.LeftButton:
|
if event.button() == Qt.LeftButton or self.in_drag_drop:
|
||||||
QTreeView.mouseReleaseEvent(self, event)
|
QTreeView.mouseReleaseEvent(self, event)
|
||||||
|
self.in_drag_drop = False
|
||||||
|
|
||||||
def mouseDoubleClickEvent(self, event):
|
def mouseDoubleClickEvent(self, event):
|
||||||
# swallow these to avoid toggling and editing at the same time
|
# swallow these to avoid toggling and editing at the same time
|
||||||
@ -639,12 +666,19 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.show_item_at_index(self._model.index_for_path(path), box=box,
|
self.show_item_at_index(self._model.index_for_path(path), box=box,
|
||||||
position=position)
|
position=position)
|
||||||
|
|
||||||
|
def expand_parent(self, idx, depth=0):
|
||||||
|
p = self._model.parent(idx)
|
||||||
|
d = 0
|
||||||
|
if p.isValid():
|
||||||
|
d = self.expand_parent(p, depth+1)
|
||||||
|
if d == 0:
|
||||||
|
self.expand(idx)
|
||||||
|
return d+1
|
||||||
|
|
||||||
def show_item_at_index(self, idx, box=False,
|
def show_item_at_index(self, idx, box=False,
|
||||||
position=QTreeView.PositionAtCenter):
|
position=QTreeView.PositionAtCenter):
|
||||||
if idx.isValid() and idx.data(Qt.UserRole).toPyObject() is not self._model.root_item:
|
if idx.isValid() and idx.data(Qt.UserRole).toPyObject() is not self._model.root_item:
|
||||||
self.expand(self._model.parent(idx)) # Needed otherwise Qt sometimes segfaults if the
|
self.expand_parent(idx)
|
||||||
# node is buried in a collapsed, off
|
|
||||||
# screen hierarchy
|
|
||||||
self.setCurrentIndex(idx)
|
self.setCurrentIndex(idx)
|
||||||
self.scrollTo(idx, position)
|
self.scrollTo(idx, position)
|
||||||
if box:
|
if box:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user