mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Enable drop indicator when dropping on Tag Browser
This commit is contained in:
parent
867fb458a2
commit
6e6435913b
@ -29,7 +29,7 @@ class TagDelegate(QItemDelegate): # {{{
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
item = index.internalPointer()
|
||||
if item.type != TagTreeItem.TAG:
|
||||
if True or item.type != TagTreeItem.TAG:
|
||||
QItemDelegate.paint(self, painter, option, index)
|
||||
return
|
||||
r = option.rect
|
||||
@ -89,7 +89,8 @@ class TagsView(QTreeView): # {{{
|
||||
self.hidden_categories = config['tag_browser_hidden_categories']
|
||||
self._model = TagsModel(db, parent=self,
|
||||
hidden_categories=self.hidden_categories,
|
||||
search_restriction=None)
|
||||
search_restriction=None,
|
||||
drag_drop_finished=self.drag_drop_finished)
|
||||
self.sort_by = sort_by
|
||||
self.tag_match = tag_match
|
||||
self.db = db
|
||||
@ -109,103 +110,6 @@ class TagsView(QTreeView): # {{{
|
||||
def database_changed(self, event, ids):
|
||||
self.refresh_required.emit()
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
md = event.mimeData()
|
||||
if md.hasFormat("application/calibre+from_library"):
|
||||
event.setDropAction(Qt.CopyAction)
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dragMoveEvent(self, event):
|
||||
allowed = False
|
||||
idx = self.indexAt(event.pos())
|
||||
m = self.model()
|
||||
p = m.parent(idx)
|
||||
if idx.isValid() and p.isValid():
|
||||
item = m.data(p, Qt.UserRole)
|
||||
fm = self.db.metadata_for_field(item.category_key)
|
||||
if item.category_key in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or\
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
allowed = True
|
||||
if allowed:
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dropEvent(self, event):
|
||||
idx = self.indexAt(event.pos())
|
||||
m = self.model()
|
||||
p = m.parent(idx)
|
||||
if idx.isValid() and p.isValid():
|
||||
item = m.data(p, Qt.UserRole)
|
||||
if item.type == TagTreeItem.CATEGORY:
|
||||
fm = self.db.metadata_for_field(item.category_key)
|
||||
if item.category_key in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or\
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
child = m.data(idx, Qt.UserRole)
|
||||
md = event.mimeData()
|
||||
mime = 'application/calibre+from_library'
|
||||
ids = list(map(int, str(md.data(mime)).split()))
|
||||
self.handle_drop(item, child, ids)
|
||||
event.accept()
|
||||
return
|
||||
event.ignore()
|
||||
|
||||
def handle_drop(self, parent, child, ids):
|
||||
# print 'Dropped ids:', ids, parent.category_key, child.tag.name
|
||||
key = parent.category_key
|
||||
if (key == 'authors' and len(ids) >= 5):
|
||||
if not confirm('<p>'+_('Changing the authors for several books can '
|
||||
'take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_drop_authors', self):
|
||||
return
|
||||
elif len(ids) > 15:
|
||||
if not confirm('<p>'+_('Changing the metadata for that many books '
|
||||
'can take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_many_changes', self):
|
||||
return
|
||||
|
||||
fm = self.db.metadata_for_field(key)
|
||||
is_multiple = fm['is_multiple']
|
||||
val = child.tag.name
|
||||
for id in ids:
|
||||
mi = self.db.get_metadata(id, index_is_id=True)
|
||||
|
||||
# Prepare to ignore the author, unless it is changed. Title is
|
||||
# always ignored -- see the call to set_metadata
|
||||
set_authors = False
|
||||
|
||||
# Author_sort cannot change explicitly. Changing the author might
|
||||
# change it.
|
||||
mi.author_sort = None # Never will change by itself.
|
||||
|
||||
if key == 'authors':
|
||||
mi.authors = [val]
|
||||
set_authors=True
|
||||
elif fm['datatype'] == 'rating':
|
||||
mi.set(key, len(val) * 2)
|
||||
elif fm['is_custom'] and fm['datatype'] == 'series':
|
||||
mi.set(key, val, extra=1.0)
|
||||
elif is_multiple:
|
||||
new_val = mi.get(key, [])
|
||||
if val in new_val:
|
||||
# Fortunately, only one field can change, so the continue
|
||||
# won't break anything
|
||||
continue
|
||||
new_val.append(val)
|
||||
mi.set(key, new_val)
|
||||
else:
|
||||
mi.set(key, val)
|
||||
self.db.set_metadata(id, mi, set_title=False,
|
||||
set_authors=set_authors, commit=False)
|
||||
self.db.commit()
|
||||
self.drag_drop_finished.emit(ids)
|
||||
|
||||
@property
|
||||
def match_all(self):
|
||||
return self.tag_match and self.tag_match.currentIndex() > 0
|
||||
@ -374,7 +278,8 @@ class TagsView(QTreeView): # {{{
|
||||
try:
|
||||
self._model = TagsModel(self.db, parent=self,
|
||||
hidden_categories=self.hidden_categories,
|
||||
search_restriction=self.search_restriction)
|
||||
search_restriction=self.search_restriction,
|
||||
drag_drop_finished=self.drag_drop_finished)
|
||||
self.setModel(self._model)
|
||||
except:
|
||||
# The DB must be gone. Set the model to None and hope that someone
|
||||
@ -469,7 +374,8 @@ class TagTreeItem(object): # {{{
|
||||
|
||||
class TagsModel(QAbstractItemModel): # {{{
|
||||
|
||||
def __init__(self, db, parent, hidden_categories=None, search_restriction=None):
|
||||
def __init__(self, db, parent, hidden_categories=None,
|
||||
search_restriction=None, drag_drop_finished=None):
|
||||
QAbstractItemModel.__init__(self, parent)
|
||||
|
||||
# must do this here because 'QPixmap: Must construct a QApplication
|
||||
@ -487,6 +393,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
':user' : QIcon(I('drawer.png')),
|
||||
'search' : QIcon(I('search.png'))})
|
||||
self.categories_with_ratings = ['authors', 'series', 'publisher', 'tags']
|
||||
self.drag_drop_finished = drag_drop_finished
|
||||
|
||||
self.icon_state_map = [None, QIcon(I('plus.png')), QIcon(I('minus.png'))]
|
||||
self.db = db
|
||||
@ -519,6 +426,82 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
tag.avg_rating = None
|
||||
TagTreeItem(parent=c, data=tag, icon_map=self.icon_state_map)
|
||||
|
||||
def mimeTypes(self):
|
||||
return ["application/calibre+from_library"]
|
||||
|
||||
def dropMimeData(self, md, action, row, column, parent):
|
||||
if not md.hasFormat("application/calibre+from_library") or \
|
||||
action != Qt.CopyAction:
|
||||
return False
|
||||
idx = parent
|
||||
p = self.parent(idx)
|
||||
if idx.isValid() and p.isValid():
|
||||
item = self.data(p, Qt.UserRole)
|
||||
fm = self.db.metadata_for_field(item.category_key)
|
||||
if item.category_key in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or \
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
child = self.data(idx, Qt.UserRole)
|
||||
mime = 'application/calibre+from_library'
|
||||
ids = list(map(int, str(md.data(mime)).split()))
|
||||
self.handle_drop(item, child, ids)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def handle_drop(self, parent, child, ids):
|
||||
# print 'Dropped ids:', ids, parent.category_key, child.tag.name
|
||||
key = parent.category_key
|
||||
if (key == 'authors' and len(ids) >= 5):
|
||||
if not confirm('<p>'+_('Changing the authors for several books can '
|
||||
'take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_drop_authors', self.parent()):
|
||||
return
|
||||
elif len(ids) > 15:
|
||||
if not confirm('<p>'+_('Changing the metadata for that many books '
|
||||
'can take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_many_changes', self.parent()):
|
||||
return
|
||||
|
||||
fm = self.db.metadata_for_field(key)
|
||||
is_multiple = fm['is_multiple']
|
||||
val = child.tag.name
|
||||
for id in ids:
|
||||
mi = self.db.get_metadata(id, index_is_id=True)
|
||||
|
||||
# Prepare to ignore the author, unless it is changed. Title is
|
||||
# always ignored -- see the call to set_metadata
|
||||
set_authors = False
|
||||
|
||||
# Author_sort cannot change explicitly. Changing the author might
|
||||
# change it.
|
||||
mi.author_sort = None # Never will change by itself.
|
||||
|
||||
if key == 'authors':
|
||||
mi.authors = [val]
|
||||
set_authors=True
|
||||
elif fm['datatype'] == 'rating':
|
||||
mi.set(key, len(val) * 2)
|
||||
elif fm['is_custom'] and fm['datatype'] == 'series':
|
||||
mi.set(key, val, extra=1.0)
|
||||
elif is_multiple:
|
||||
new_val = mi.get(key, [])
|
||||
if val in new_val:
|
||||
# Fortunately, only one field can change, so the continue
|
||||
# won't break anything
|
||||
continue
|
||||
new_val.append(val)
|
||||
mi.set(key, new_val)
|
||||
else:
|
||||
mi.set(key, val)
|
||||
self.db.set_metadata(id, mi, set_title=False,
|
||||
set_authors=set_authors, commit=False)
|
||||
self.db.commit()
|
||||
self.drag_drop_finished.emit(ids)
|
||||
|
||||
|
||||
|
||||
def set_search_restriction(self, s):
|
||||
self.search_restriction = s
|
||||
|
||||
@ -655,7 +638,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
return ans
|
||||
|
||||
def supportedDropActions(self):
|
||||
return Qt.CopyAction|Qt.MoveAction
|
||||
return Qt.CopyAction
|
||||
|
||||
def path_for_index(self, index):
|
||||
ans = []
|
||||
|
Loading…
x
Reference in New Issue
Block a user