diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index f2c1fd6065..f42dac8f93 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1053,6 +1053,25 @@ def rating_font(): global _rating_font return _rating_font +def elided_text(text, font=None, width=300, pos='middle'): + ''' Return a version of text that is n wider than width pixels when + rendered, replacing characters from the left, middle or right (as per pos) + of the string with an ellipsis. Results in a string much closer to the + limit than Qt's elidedText().''' + from PyQt4.Qt import QFontMetrics, QApplication + fm = QApplication.fontMetrics() if font is None else QFontMetrics(font) + delta = 4 + ellipsis = u'\u2026' + + def remove_middle(x): + mid = len(x) // 2 + return x[:max(0, mid - (delta//2))] + ellipsis + x[mid + (delta//2):] + + chomp = {'middle':remove_middle, 'left':lambda x:(ellipsis + x[delta:]), 'right':lambda x:(x[:-delta] + ellipsis)}[pos] + while len(text) > delta and fm.width(text) > width: + text = chomp(text) + return unicode(text) + def find_forms(srcdir): base = os.path.join(srcdir, 'calibre', 'gui2') forms = [] diff --git a/src/calibre/gui2/tweak_book/__init__.py b/src/calibre/gui2/tweak_book/__init__.py index 57eead5d0f..72aec0661c 100644 --- a/src/calibre/gui2/tweak_book/__init__.py +++ b/src/calibre/gui2/tweak_book/__init__.py @@ -27,13 +27,6 @@ def set_current_container(container): global _current_container _current_container = container -def elided_text(font, text, width=200, mode=None): - from PyQt4.Qt import QFontMetrics, Qt - if mode is None: - mode = Qt.ElideMiddle - fm = QFontMetrics(font) - return unicode(fm.elidedText(text, mode, int(width))) - class NonReplaceDict(dict): def __setitem__(self, k, v): diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index 82c272fbb2..f198f6818a 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -169,6 +169,13 @@ class Boss(QObject): self.gui.file_list.build(container, preserve_state=False) self.gui.action_save.setEnabled(False) self.update_global_history_actions() + recent_books = list(tprefs.get('recent-books', [])) + path = container.path_to_ebook + if path in recent_books: + recent_books.remove(path) + recent_books.insert(0, path) + tprefs['recent-books'] = recent_books[:10] + self.gui.update_recent_books() def update_editors_from_container(self, container=None): c = container or current_container() diff --git a/src/calibre/gui2/tweak_book/file_list.py b/src/calibre/gui2/tweak_book/file_list.py index 32e221fb54..224efff402 100644 --- a/src/calibre/gui2/tweak_book/file_list.py +++ b/src/calibre/gui2/tweak_book/file_list.py @@ -20,8 +20,8 @@ from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS from calibre.ebooks.oeb.polish.container import guess_type, OEB_FONTS from calibre.ebooks.oeb.polish.cover import ( get_cover_page_name, get_raster_cover_name, is_raster_image) -from calibre.gui2 import error_dialog, choose_files, question_dialog -from calibre.gui2.tweak_book import current_container, elided_text +from calibre.gui2 import error_dialog, choose_files, question_dialog, elided_text +from calibre.gui2.tweak_book import current_container from calibre.gui2.tweak_book.editor import syntax_from_mime from calibre.gui2.tweak_book.templates import template_for from calibre.utils.icu import sort_key @@ -310,11 +310,11 @@ class FileList(QTreeWidget): cn = unicode(ci.data(0, NAME_ROLE).toString()) mt = unicode(ci.data(0, MIME_ROLE).toString()) cat = unicode(ci.data(0, CATEGORY_ROLE).toString()) - m.addAction(QIcon(I('modified.png')), _('&Rename %s') % (elided_text(self.font(), cn)), self.edit_current_item) + m.addAction(QIcon(I('modified.png')), _('&Rename %s') % (elided_text(cn)), self.edit_current_item) if is_raster_image(mt): - m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % elided_text(self.font(), cn), partial(self.mark_as_cover, cn)) + m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % elided_text(cn), partial(self.mark_as_cover, cn)) elif current_container().SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == 'text': - m.addAction(QIcon(I('default_cover.png')), _('Mark %s as title/cover page') % elided_text(self.font(), cn), partial(self.mark_as_titlepage, cn)) + m.addAction(QIcon(I('default_cover.png')), _('Mark %s as title/cover page') % elided_text(cn), partial(self.mark_as_titlepage, cn)) selected_map = defaultdict(list) for item in sel: @@ -358,7 +358,7 @@ class FileList(QTreeWidget): move_to_start = question_dialog(self, _('Not first item'), _( '%s is not the first text item. You should only mark the' ' first text item as cover. Do you want to make it the' - ' first item?') % elided_text(self.font(), name)) + ' first item?') % elided_text(name)) self.mark_requested.emit(name, 'titlepage:%r' % move_to_start) def keyPressEvent(self, ev): diff --git a/src/calibre/gui2/tweak_book/ui.py b/src/calibre/gui2/tweak_book/ui.py index 1ae6c6bcc9..15745fff8b 100644 --- a/src/calibre/gui2/tweak_book/ui.py +++ b/src/calibre/gui2/tweak_book/ui.py @@ -13,9 +13,10 @@ from PyQt4.Qt import ( QVBoxLayout, QStackedWidget, QTabWidget, QImage, QPixmap, pyqtSignal) from calibre.constants import __appname__, get_version +from calibre.gui2 import elided_text from calibre.gui2.keyboard import Manager as KeyboardManager from calibre.gui2.main_window import MainWindow -from calibre.gui2.tweak_book import current_container, tprefs, actions, elided_text +from calibre.gui2.tweak_book import current_container, tprefs, actions from calibre.gui2.tweak_book.file_list import FileListWidget from calibre.gui2.tweak_book.job import BlockingJob from calibre.gui2.tweak_book.boss import Boss @@ -158,8 +159,8 @@ class Main(MainWindow): def show_status_message(self, msg, timeout=5): self.status_bar.showMessage(msg, int(timeout*1000)) - def elided_text(self, text, width=200, mode=Qt.ElideMiddle): - return elided_text(self.font(), text, width=width, mode=mode) + def elided_text(self, text, width=300): + return elided_text(text, font=self.font(), width=width) @property def editor_tabs(self): @@ -281,6 +282,8 @@ class Main(MainWindow): f = b.addMenu(_('&File')) f.addAction(self.action_new_file) f.addAction(self.action_open_book) + self.recent_books_menu = f.addMenu(_('&Recently opened books')) + self.update_recent_books() f.addSeparator() f.addAction(self.action_save) f.addAction(self.action_save_copy) @@ -336,6 +339,13 @@ class Main(MainWindow): e.addSeparator() a(self.action_go_to_line) + def update_recent_books(self): + m = self.recent_books_menu + m.clear() + books = tprefs.get('recent-books', []) + for path in books: + m.addAction(self.elided_text(path, width=500), partial(self.boss.open_book, path=path)) + def create_toolbars(self): def create(text, name): name += '-bar'