mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
ec30a7d65f
@ -291,6 +291,9 @@ class TagBrowserMixin(object): # {{{
|
|||||||
if n:
|
if n:
|
||||||
n = '%s:\n %s\n%s:\n %s'%(_('Item'), orig_name, _('Children'), n)
|
n = '%s:\n %s\n%s:\n %s'%(_('Item'), orig_name, _('Children'), n)
|
||||||
if n:
|
if n:
|
||||||
|
# Use a new "see this again" name to force the dialog to appear at
|
||||||
|
# least once, thus announcing the new feature.
|
||||||
|
skip_dialog_name = 'tag_item_delete_hierarchical'
|
||||||
if restrict_to_book_ids:
|
if restrict_to_book_ids:
|
||||||
msg = _('%s and its children will be deleted from books '
|
msg = _('%s and its children will be deleted from books '
|
||||||
'in the Virtual library. Are you sure?')%orig_name
|
'in the Virtual library. Are you sure?')%orig_name
|
||||||
@ -298,20 +301,21 @@ class TagBrowserMixin(object): # {{{
|
|||||||
msg = _('%s and its children will be deleted from all books. '
|
msg = _('%s and its children will be deleted from all books. '
|
||||||
'Are you sure?')%orig_name
|
'Are you sure?')%orig_name
|
||||||
else:
|
else:
|
||||||
|
skip_dialog_name='tag_item_delete',
|
||||||
if restrict_to_book_ids:
|
if restrict_to_book_ids:
|
||||||
msg = _('%s will be deleted from books in the Virtual library. Are you sure?')%orig_name
|
msg = _('%s will be deleted from books in the Virtual library. Are you sure?')%orig_name
|
||||||
else:
|
else:
|
||||||
msg = _('%s will be deleted from all books. Are you sure?')%orig_name
|
msg = _('%s will be deleted from all books. Are you sure?')%orig_name
|
||||||
|
|
||||||
if not question_dialog(self.tags_view,
|
if not question_dialog(self.tags_view,
|
||||||
title=_('Delete item'),
|
title=_('Delete item'),
|
||||||
msg='<p>'+ msg,
|
msg='<p>'+ msg,
|
||||||
det_msg=n,
|
det_msg=n,
|
||||||
# Change the skip name because functionality has greatly changed
|
skip_dialog_name=skip_dialog_name,
|
||||||
skip_dialog_name='tag_item_delete_hierarchical',
|
|
||||||
skip_dialog_msg=_('Show this confirmation again')):
|
skip_dialog_msg=_('Show this confirmation again')):
|
||||||
return
|
return
|
||||||
ids_to_remove = [item_id]
|
ids_to_remove = []
|
||||||
|
if item_id is not None:
|
||||||
|
ids_to_remove.append(item_id)
|
||||||
for child in children:
|
for child in children:
|
||||||
if child.tag.is_editable:
|
if child.tag.is_editable:
|
||||||
ids_to_remove.append(child.tag.id)
|
ids_to_remove.append(child.tag.id)
|
||||||
|
@ -172,7 +172,6 @@ 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'))
|
||||||
@ -333,7 +332,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
self.unsetCursor()
|
self.unsetCursor()
|
||||||
if not event.buttons() & Qt.LeftButton:
|
if not event.buttons() & Qt.LeftButton:
|
||||||
return
|
return
|
||||||
if self.in_drag_drop or not dex.isValid():
|
if not dex.isValid():
|
||||||
QTreeView.mouseMoveEvent(self, event)
|
QTreeView.mouseMoveEvent(self, event)
|
||||||
return
|
return
|
||||||
# don't start drag/drop until the mouse has moved a bit.
|
# don't start drag/drop until the mouse has moved a bit.
|
||||||
@ -341,12 +340,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
QApplication.startDragDistance()):
|
QApplication.startDragDistance()):
|
||||||
QTreeView.mouseMoveEvent(self, event)
|
QTreeView.mouseMoveEvent(self, event)
|
||||||
return
|
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:
|
if not self._model.flags(dex) & Qt.ItemIsDragEnabled:
|
||||||
QTreeView.mouseMoveEvent(self, event)
|
QTreeView.mouseMoveEvent(self, event)
|
||||||
return
|
return
|
||||||
@ -367,12 +361,6 @@ class TagsView(QTreeView): # {{{
|
|||||||
else:
|
else:
|
||||||
drag.exec_(Qt.CopyAction)
|
drag.exec_(Qt.CopyAction)
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
|
||||||
# Swallow everything except leftButton so context menus work correctly
|
|
||||||
if event.button() == Qt.LeftButton or self.in_drag_drop:
|
|
||||||
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
|
||||||
pass
|
pass
|
||||||
@ -458,15 +446,17 @@ class TagsView(QTreeView): # {{{
|
|||||||
return
|
return
|
||||||
if action == 'delete_item_in_vl':
|
if action == 'delete_item_in_vl':
|
||||||
tag = index.tag
|
tag = index.tag
|
||||||
|
id_ = tag.id if tag.is_editable else None
|
||||||
children = index.child_tags()
|
children = index.child_tags()
|
||||||
self.tag_item_delete.emit(key, tag.id, tag.original_name,
|
self.tag_item_delete.emit(key, id_, tag.original_name,
|
||||||
self.model().get_book_ids_to_use(),
|
self.model().get_book_ids_to_use(),
|
||||||
children)
|
children)
|
||||||
return
|
return
|
||||||
if action == 'delete_item_no_vl':
|
if action == 'delete_item_no_vl':
|
||||||
tag = index.tag
|
tag = index.tag
|
||||||
|
id_ = tag.id if tag.is_editable else None
|
||||||
children = index.child_tags()
|
children = index.child_tags()
|
||||||
self.tag_item_delete.emit(key, tag.id, tag.original_name,
|
self.tag_item_delete.emit(key, id_, tag.original_name,
|
||||||
None, children)
|
None, children)
|
||||||
return
|
return
|
||||||
if action == 'open_editor':
|
if action == 'open_editor':
|
||||||
@ -618,7 +608,6 @@ class TagsView(QTreeView): # {{{
|
|||||||
_('Rename %s')%display_name(tag),
|
_('Rename %s')%display_name(tag),
|
||||||
partial(self.context_menu_handler, action='edit_item_no_vl',
|
partial(self.context_menu_handler, action='edit_item_no_vl',
|
||||||
index=index, category=key))
|
index=index, category=key))
|
||||||
if tag.is_editable:
|
|
||||||
if key in ('tags', 'series', 'publisher') or \
|
if key in ('tags', 'series', 'publisher') or \
|
||||||
self._model.db.field_metadata.is_custom_field(key):
|
self._model.db.field_metadata.is_custom_field(key):
|
||||||
if self.model().get_in_vl():
|
if self.model().get_in_vl():
|
||||||
@ -631,6 +620,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
_('Delete %s')%display_name(tag),
|
_('Delete %s')%display_name(tag),
|
||||||
partial(self.context_menu_handler, action='delete_item_no_vl',
|
partial(self.context_menu_handler, action='delete_item_no_vl',
|
||||||
key=key, index=tag_item))
|
key=key, index=tag_item))
|
||||||
|
if tag.is_editable:
|
||||||
if key == 'authors':
|
if key == 'authors':
|
||||||
self.context_menu.addAction(_('Edit sort for %s')%display_name(tag),
|
self.context_menu.addAction(_('Edit sort for %s')%display_name(tag),
|
||||||
partial(self.context_menu_handler,
|
partial(self.context_menu_handler,
|
||||||
@ -869,9 +859,14 @@ class TagsView(QTreeView): # {{{
|
|||||||
return
|
return
|
||||||
|
|
||||||
if src_is_tb:
|
if src_is_tb:
|
||||||
src = json_loads(bytes(event.mimeData().data('application/calibre+from_tag_browser')))
|
src_json = json_loads(bytes(event.mimeData().data('application/calibre+from_tag_browser')))
|
||||||
if len(src) == 1:
|
if len(src_json) > 1:
|
||||||
src_item = self._model.get_node(self._model.index_for_path(src[0][5]))
|
# Should never have multiple mimedata from the tag browser
|
||||||
|
return
|
||||||
|
if src_is_tb:
|
||||||
|
src_md = src_json[0]
|
||||||
|
src_item = self._model.get_node(self._model.index_for_path(src_md[5]))
|
||||||
|
# Check if this is an intra-hierarchical-category drag/drop
|
||||||
if (src_item.type == TagTreeItem.TAG and
|
if (src_item.type == TagTreeItem.TAG and
|
||||||
src_item.tag.category == item.tag.category and
|
src_item.tag.category == item.tag.category and
|
||||||
not item.temporary and
|
not item.temporary and
|
||||||
@ -879,29 +874,39 @@ class TagsView(QTreeView): # {{{
|
|||||||
event.setDropAction(Qt.MoveAction)
|
event.setDropAction(Qt.MoveAction)
|
||||||
self.setDropIndicatorShown(True)
|
self.setDropIndicatorShown(True)
|
||||||
return
|
return
|
||||||
|
# We aren't dropping an item on its own category. Check if the dest is
|
||||||
|
# not a user category and can be dropped on. This covers drops from the
|
||||||
|
# booklist. It is OK to drop onto virtual nodes
|
||||||
if item.type == TagTreeItem.TAG and self._model.flags(index) & Qt.ItemIsDropEnabled:
|
if item.type == TagTreeItem.TAG and self._model.flags(index) & Qt.ItemIsDropEnabled:
|
||||||
event.setDropAction(Qt.CopyAction)
|
event.setDropAction(Qt.CopyAction)
|
||||||
self.setDropIndicatorShown(not src_is_tb)
|
self.setDropIndicatorShown(not src_is_tb)
|
||||||
return
|
return
|
||||||
|
# Now see if we are on a user category and the source can be dropped there
|
||||||
if item.type == TagTreeItem.CATEGORY and not item.is_gst:
|
if item.type == TagTreeItem.CATEGORY and not item.is_gst:
|
||||||
fm_dest = self.db.metadata_for_field(item.category_key)
|
fm_dest = self.db.metadata_for_field(item.category_key)
|
||||||
if fm_dest['kind'] == 'user':
|
if fm_dest['kind'] == 'user':
|
||||||
if src_is_tb:
|
if src_is_tb:
|
||||||
|
# src_md and src_item are initialized above
|
||||||
if event.dropAction() == Qt.MoveAction:
|
if event.dropAction() == Qt.MoveAction:
|
||||||
# src is initialized above
|
# can move only from user categories
|
||||||
for s in src:
|
if (src_md[0] == TagTreeItem.TAG and
|
||||||
if s[0] == TagTreeItem.TAG and \
|
(not src_md[1].startswith('@') or src_md[2])):
|
||||||
(not s[1].startswith('@') or s[2]):
|
|
||||||
return
|
return
|
||||||
|
# can't copy virtual nodes into a user category
|
||||||
|
if src_item.tag.is_editable:
|
||||||
self.setDropIndicatorShown(True)
|
self.setDropIndicatorShown(True)
|
||||||
return
|
return
|
||||||
md = event.mimeData()
|
md = event.mimeData()
|
||||||
|
# Check for drag to user category from the book list. Can handle
|
||||||
|
# only non-multiple columns, except for some unknown reason authors
|
||||||
if hasattr(md, 'column_name'):
|
if hasattr(md, 'column_name'):
|
||||||
fm_src = self.db.metadata_for_field(md.column_name)
|
fm_src = self.db.metadata_for_field(md.column_name)
|
||||||
if md.column_name in ['authors', 'publisher', 'series'] or \
|
if md.column_name in ['authors', 'publisher', 'series'] or \
|
||||||
(fm_src['is_custom'] and (
|
(fm_src['is_custom'] and
|
||||||
(fm_src['datatype'] in ['series', 'text', 'enumeration'] and not fm_src['is_multiple']) or (
|
((fm_src['datatype'] in ['series', 'text', 'enumeration'] and
|
||||||
fm_src['datatype'] == 'composite' and fm_src['display'].get('make_category', False)))):
|
not fm_src['is_multiple']) or
|
||||||
|
(fm_src['datatype'] == 'composite' and
|
||||||
|
fm_src['display'].get('make_category', False)))):
|
||||||
self.setDropIndicatorShown(True)
|
self.setDropIndicatorShown(True)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user