Implement double clicking on image to jump to its references

This commit is contained in:
Kovid Goyal 2015-01-21 12:53:08 +05:30
parent 484bfaed72
commit f054562ecb
3 changed files with 49 additions and 14 deletions

View File

@ -55,15 +55,15 @@ def file_data(container):
yield File(name, posixpath.dirname(name), posixpath.basename(name), safe_size(container, name), yield File(name, posixpath.dirname(name), posixpath.basename(name), safe_size(container, name),
get_category(name, container.mime_map.get(name, ''))) get_category(name, container.mime_map.get(name, '')))
Image = namedtuple('Image', 'name mime_type usage size basename width height') Image = namedtuple('Image', 'name mime_type usage size basename id width height')
L = namedtuple('Location', 'name line_number offset word') L = namedtuple('Location', 'name line_number text_on_line word_on_line character_offset')
def Location(name, line_number=None, offset=0, word=None): def Location(name, line_number=None, text_on_line=None, word_on_line=None, character_offset=None):
return L(name, line_number, offset, word) return L(name, line_number, text_on_line, word_on_line, character_offset)
def sort_locations(locations): def sort_locations(locations):
def sort_key(l): def sort_key(l):
return (numeric_sort_key(l.name), l.line_number, l.offset, l.word) return (numeric_sort_key(l.name), l.line_number, l.character_offset)
return sorted(locations, key=sort_key) return sorted(locations, key=sort_key)
def link_data(container): def link_data(container):
@ -76,13 +76,13 @@ def link_data(container):
if target and container.exists(target): if target and container.exists(target):
mt = container.mime_map.get(target) mt = container.mime_map.get(target)
if mt and mt.startswith('image/'): if mt and mt.startswith('image/'):
image_usage[target].add(Location(name, line_number, offset)) image_usage[target].add(Location(name, line_number, text_on_line=href))
image_data = [] image_data = []
for name, mt in container.mime_map.iteritems(): for name, mt in container.mime_map.iteritems():
if mt.startswith('image/') and container.exists(name): if mt.startswith('image/') and container.exists(name):
image_data.append(Image(name, mt, sort_locations(image_usage.get(name, set())), safe_size(container, name), image_data.append(Image(name, mt, sort_locations(image_usage.get(name, set())), safe_size(container, name),
posixpath.basename(name), *safe_img_data(container, name, mt))) posixpath.basename(name), len(image_data), *safe_img_data(container, name, mt)))
return tuple(image_data) return tuple(image_data)
def gather_data(container): def gather_data(container):

View File

@ -1162,9 +1162,7 @@ class Boss(QObject):
def reports_edit_requested(self, location): def reports_edit_requested(self, location):
name = location.name name = location.name
mt = current_container().mime_map.get(name, guess_type(name)) mt = current_container().mime_map.get(name, guess_type(name))
editor = self.edit_file_requested(name, None, mt) self.edit_file_requested(name, None, mt)
if editor is not None:
pass
def image_activated(self, name): def image_activated(self, name):
mt = current_container().mime_map.get(name, guess_type(name)) mt = current_container().mime_map.get(name, guess_type(name))
@ -1250,7 +1248,7 @@ class Boss(QObject):
def edit_file_requested(self, name, syntax, mime): def edit_file_requested(self, name, syntax, mime):
if name in editors: if name in editors:
self.gui.central.show_editor(editors[name]) self.gui.central.show_editor(editors[name])
return return editors[name]
syntax = syntax or syntax_from_mime(name, mime) syntax = syntax or syntax_from_mime(name, mime)
if not syntax: if not syntax:
return error_dialog( return error_dialog(

View File

@ -10,7 +10,9 @@ from threading import Thread
from future_builtins import map from future_builtins import map
from operator import itemgetter from operator import itemgetter
from functools import partial from functools import partial
from collections import defaultdict
import regex
from PyQt5.Qt import ( from PyQt5.Qt import (
QSize, QStackedLayout, QLabel, QVBoxLayout, Qt, QWidget, pyqtSignal, QSize, QStackedLayout, QLabel, QVBoxLayout, Qt, QWidget, pyqtSignal,
QAbstractTableModel, QTableView, QSortFilterProxyModel, QIcon, QListWidget, QAbstractTableModel, QTableView, QSortFilterProxyModel, QIcon, QListWidget,
@ -18,6 +20,7 @@ from PyQt5.Qt import (
QStyledItemDelegate, QModelIndex, QRect, QStyle, QPalette, QTimer, QMenu) QStyledItemDelegate, QModelIndex, QRect, QStyle, QPalette, QTimer, QMenu)
from calibre import human_readable, fit_image from calibre import human_readable, fit_image
from calibre.ebooks.oeb.polish.container import guess_type
from calibre.ebooks.oeb.polish.report import gather_data, Location from calibre.ebooks.oeb.polish.report import gather_data, Location
from calibre.gui2 import error_dialog, question_dialog from calibre.gui2 import error_dialog, question_dialog
from calibre.gui2.tweak_book import current_container, tprefs from calibre.gui2.tweak_book import current_container, tprefs
@ -254,6 +257,39 @@ class FilesWidget(QWidget):
# }}} # }}}
class Jump(object): # {{{
def __init__(self):
self.pos_map = defaultdict(lambda : -1)
def clear(self):
self.pos_map.clear()
def __call__(self, key, locations):
self.pos_map[key] = (self.pos_map[key] + 1) % len(locations)
loc = locations[self.pos_map[key]]
from calibre.gui2.tweak_book.boss import get_boss
boss = get_boss()
if boss is None:
return
name = loc.name
mt = current_container().mime_map.get(name, guess_type(name))
editor = boss.edit_file_requested(name, None, mt)
if editor is None:
return
editor = editor.editor
if loc.line_number is not None:
block = editor.document().findBlockByNumber(loc.line_number - 1) # blockNumber() is zero based
if not block.isValid():
return
c = editor.textCursor()
c.setPosition(block.position(), c.MoveAnchor)
editor.setTextCursor(c)
if loc.text_on_line is not None:
editor.find(regex.compile(regex.escape(loc.text_on_line)))
jump = Jump() # }}}
# Images {{{ # Images {{{
class ImagesDelegate(QStyledItemDelegate): class ImagesDelegate(QStyledItemDelegate):
@ -384,9 +420,9 @@ class ImagesWidget(QWidget):
QTimer.singleShot(0, self.files.resizeRowsToContents) QTimer.singleShot(0, self.files.resizeRowsToContents)
def double_clicked(self, index): def double_clicked(self, index):
location = self.model.location(index) entry = index.data(Qt.UserRole)
if location is not None: if entry is not None:
self.edit_requested.emit(location) jump((id(self), entry.id), entry.usage)
def customize_context_menu(self, menu, selected_locations, current_location): def customize_context_menu(self, menu, selected_locations, current_location):
if current_location is not None: if current_location is not None:
@ -436,6 +472,7 @@ class ReportsWidget(QWidget):
self.reports.setCurrentRow(current_page) self.reports.setCurrentRow(current_page)
def __call__(self, data): def __call__(self, data):
jump.clear()
self.files(data) self.files(data)
self.images(data) self.images(data)