Edit book: Add a tool to browse all images in the book with their thumbnails. Useful for visually locating an image. To launch it, use View->Browse images in book.

This commit is contained in:
Kovid Goyal 2013-12-19 11:00:30 +05:30
parent c3df19e437
commit 89236b5100
3 changed files with 64 additions and 12 deletions

View File

@ -106,6 +106,7 @@ class Boss(QObject):
self.gui.check_book.check_requested.connect(self.check_requested) self.gui.check_book.check_requested.connect(self.check_requested)
self.gui.check_book.fix_requested.connect(self.fix_requested) self.gui.check_book.fix_requested.connect(self.fix_requested)
self.gui.toc_view.navigate_requested.connect(self.link_clicked) self.gui.toc_view.navigate_requested.connect(self.link_clicked)
self.gui.image_browser.image_activated.connect(self.image_activated)
def preferences(self): def preferences(self):
p = Preferences(self.gui) p = Preferences(self.gui)
@ -817,6 +818,15 @@ class Boss(QObject):
replace_file(current_container(), name, path, basename, force_mt) replace_file(current_container(), name, path, basename, force_mt)
self.apply_container_update_to_gui() self.apply_container_update_to_gui()
def browse_images(self):
self.gui.image_browser.refresh()
self.gui.image_browser.show()
self.gui.image_browser.raise_()
def image_activated(self, name):
mt = current_container().mime_map.get(name, guess_type(name))
self.edit_file_requested(name, None, mt)
def sync_editor_to_preview(self, name, lnum): def sync_editor_to_preview(self, name, lnum):
editor = self.edit_file(name, 'html') editor = self.edit_file(name, 'html')
self.ignore_preview_to_editor_sync = True self.ignore_preview_to_editor_sync = True

View File

@ -12,7 +12,7 @@ from PyQt4.Qt import (
QDialog, QGridLayout, QDialogButtonBox, QSize, QListView, QStyledItemDelegate, QDialog, QGridLayout, QDialogButtonBox, QSize, QListView, QStyledItemDelegate,
QLabel, QPixmap, QApplication, QSizePolicy, QAbstractListModel, QVariant, QLabel, QPixmap, QApplication, QSizePolicy, QAbstractListModel, QVariant,
Qt, QRect, QPainter, QModelIndex, QSortFilterProxyModel, QLineEdit, Qt, QRect, QPainter, QModelIndex, QSortFilterProxyModel, QLineEdit,
QToolButton, QIcon, QFormLayout) QToolButton, QIcon, QFormLayout, pyqtSignal)
from calibre import fit_image from calibre import fit_image
from calibre.constants import plugins from calibre.constants import plugins
@ -160,12 +160,20 @@ class Images(QAbstractListModel):
def __init__(self, parent): def __init__(self, parent):
QAbstractListModel.__init__(self, parent) QAbstractListModel.__init__(self, parent)
self.icon_size = parent.iconSize() self.icon_size = parent.iconSize()
self.build()
def build(self):
c = current_container() c = current_container()
self.image_names = [] self.image_names = []
self.image_cache = {}
if c is not None:
for name in sorted(c.mime_map, key=sort_key): for name in sorted(c.mime_map, key=sort_key):
if c.mime_map[name].startswith('image/'): if c.mime_map[name].startswith('image/'):
self.image_names.append(name) self.image_names.append(name)
self.image_cache = {}
def refresh(self):
self.build()
self.reset()
def rowCount(self, *args): def rowCount(self, *args):
return len(self.image_names) return len(self.image_names)
@ -181,8 +189,12 @@ class Images(QAbstractListModel):
class InsertImage(Dialog): class InsertImage(Dialog):
def __init__(self, parent=None): image_activated = pyqtSignal(object)
Dialog.__init__(self, _('Choose an image'), 'insert-image-dialog', parent)
def __init__(self, parent=None, for_browsing=False):
self.for_browsing = for_browsing
Dialog.__init__(self, _('Images in book') if for_browsing else _('Choose an image'),
'browse-image-dialog' if for_browsing else 'insert-image-dialog', parent)
self.chosen_image = None self.chosen_image = None
self.chosen_image_is_external = False self.chosen_image_is_external = False
@ -196,6 +208,8 @@ class InsertImage(Dialog):
self.la1 = la = QLabel(_('&Existing images in the book')) self.la1 = la = QLabel(_('&Existing images in the book'))
la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
l.addWidget(la, 0, 0, 1, 2) l.addWidget(la, 0, 0, 1, 2)
if self.for_browsing:
la.setVisible(False)
self.view = v = QListView(self) self.view = v = QListView(self)
v.setViewMode(v.IconMode) v.setViewMode(v.IconMode)
@ -212,10 +226,12 @@ class InsertImage(Dialog):
v.setItemDelegate(self.d) v.setItemDelegate(self.d)
self.model = Images(self.view) self.model = Images(self.view)
self.fm = fm = QSortFilterProxyModel(self.view) self.fm = fm = QSortFilterProxyModel(self.view)
self.fm.setDynamicSortFilter(self.for_browsing)
fm.setSourceModel(self.model) fm.setSourceModel(self.model)
fm.setFilterCaseSensitivity(False) fm.setFilterCaseSensitivity(False)
v.setModel(fm) v.setModel(fm)
l.addWidget(v, 1, 0, 1, 2) l.addWidget(v, 1, 0, 1, 2)
v.pressed.connect(self.pressed)
la.setBuddy(v) la.setBuddy(v)
self.filter = f = QLineEdit(self) self.filter = f = QLineEdit(self)
@ -228,11 +244,23 @@ class InsertImage(Dialog):
f.textChanged.connect(self.filter_changed) f.textChanged.connect(self.filter_changed)
l.addWidget(self.bb, 3, 0, 1, 2) l.addWidget(self.bb, 3, 0, 1, 2)
if self.for_browsing:
self.bb.clear()
self.bb.addButton(self.bb.Close)
b = self.refresh_button = self.bb.addButton(_('&Refresh'), self.bb.ActionRole)
b.clicked.connect(self.refresh)
b.setIcon(QIcon(I('view-refresh.png')))
b.setToolTip(_('Refresh the displayed images'))
self.setAttribute(Qt.WA_DeleteOnClose, False)
else:
b = self.import_button = self.bb.addButton(_('&Import image'), self.bb.ActionRole) b = self.import_button = self.bb.addButton(_('&Import image'), self.bb.ActionRole)
b.clicked.connect(self.import_image) b.clicked.connect(self.import_image)
b.setIcon(QIcon(I('view-image.png'))) b.setIcon(QIcon(I('view-image.png')))
b.setToolTip(_('Import an image from elsewhere in your computer')) b.setToolTip(_('Import an image from elsewhere in your computer'))
def refresh(self):
self.model.refresh()
def import_image(self): def import_image(self):
path = choose_files(self, 'tweak-book-choose-image-for-import', _('Choose Image'), path = choose_files(self, 'tweak-book-choose-image-for-import', _('Choose Image'),
filters=[(_('Images'), ('jpg', 'jpeg', 'png', 'gif', 'svg'))], all_files=True, select_only_single_file=True) filters=[(_('Images'), ('jpg', 'jpeg', 'png', 'gif', 'svg'))], all_files=True, select_only_single_file=True)
@ -246,7 +274,13 @@ class InsertImage(Dialog):
self.accept() self.accept()
self.chosen_image_is_external = (d.filename, path) self.chosen_image_is_external = (d.filename, path)
def pressed(self, index):
if QApplication.mouseButtons() & Qt.LeftButton:
self.activated(index)
def activated(self, index): def activated(self, index):
if self.for_browsing:
return self.image_activated.emit(unicode(index.data().toString()))
self.chosen_image_is_external = False self.chosen_image_is_external = False
self.accept() self.accept()

View File

@ -29,11 +29,12 @@ from calibre.gui2.tweak_book.search import SearchPanel
from calibre.gui2.tweak_book.check import Check from calibre.gui2.tweak_book.check import Check
from calibre.gui2.tweak_book.toc import TOCViewer from calibre.gui2.tweak_book.toc import TOCViewer
from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions
from calibre.gui2.tweak_book.editor.insert_resource import InsertImage
def open_donate(): def open_donate():
open_url(QUrl('http://calibre-ebook.com/donate')) open_url(QUrl('http://calibre-ebook.com/donate'))
class Central(QStackedWidget): class Central(QStackedWidget): # {{{
' The central widget, hosts the editors ' ' The central widget, hosts the editors '
@ -164,8 +165,9 @@ class Central(QStackedWidget):
menu.exec_(self.editor_tabs.tabBar().mapToGlobal(event.pos())) menu.exec_(self.editor_tabs.tabBar().mapToGlobal(event.pos()))
return True return True
# }}}
class CursorPositionWidget(QWidget): class CursorPositionWidget(QWidget): # {{{
def __init__(self, parent): def __init__(self, parent):
QWidget.__init__(self, parent) QWidget.__init__(self, parent)
@ -183,6 +185,7 @@ class CursorPositionWidget(QWidget):
self.la.setText('') self.la.setText('')
else: else:
self.la.setText(_('Line: {0} : {1}').format(line, col)) self.la.setText(_('Line: {0} : {1}').format(line, col))
# }}}
class Main(MainWindow): class Main(MainWindow):
@ -205,6 +208,7 @@ class Main(MainWindow):
self.setCentralWidget(self.central) self.setCentralWidget(self.central)
self.check_book = Check(self) self.check_book = Check(self)
self.toc_view = TOCViewer(self) self.toc_view = TOCViewer(self)
self.image_browser = InsertImage(self, for_browsing=True)
self.create_actions() self.create_actions()
self.create_toolbars() self.create_toolbars()
@ -374,6 +378,9 @@ class Main(MainWindow):
self.action_help = reg( self.action_help = reg(
'help.png', _('User &Manual'), lambda : open_url(QUrl('http://manual.calibre-ebook.com/edit.html')), 'user-manual', 'F1', _( 'help.png', _('User &Manual'), lambda : open_url(QUrl('http://manual.calibre-ebook.com/edit.html')), 'user-manual', 'F1', _(
'Show User Manual')) 'Show User Manual'))
self.action_browse_images = reg(
'view-image.png', _('&Browse images in book'), self.boss.browse_images, 'browse-images', (), _(
'Browse images in the books visually'))
def create_menubar(self): def create_menubar(self):
p, q = self.create_application_menubar() p, q = self.create_application_menubar()
@ -423,6 +430,7 @@ class Main(MainWindow):
e.addAction(ac) e.addAction(ac)
elif name.endswith('-bar'): elif name.endswith('-bar'):
t.addAction(ac) t.addAction(ac)
e.addAction(self.action_browse_images)
e.addSeparator() e.addSeparator()
e.addAction(self.action_close_current_tab) e.addAction(self.action_close_current_tab)
e.addAction(self.action_close_all_but_current_tab) e.addAction(self.action_close_all_but_current_tab)