From 4f52525c9252caa181a9b9eff79e1c0ce0e7f694 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Sep 2010 10:29:47 -0600 Subject: [PATCH 1/6] Fix #6729 (Missing XPath statement during batch convesion) --- src/calibre/devices/apple/driver.py | 2 +- src/calibre/gui2/convert/bulk.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index afd7958265..c6abe595b6 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -82,7 +82,7 @@ class ITUNES(DriverBase): ''' name = 'Apple device interface' - gui_name = 'Apple device' + gui_name = _('Apple device') icon = I('devices/ipad.png') description = _('Communicate with iTunes/iBooks.') supported_platforms = ['osx','windows'] diff --git a/src/calibre/gui2/convert/bulk.py b/src/calibre/gui2/convert/bulk.py index f0fdf9a9a1..1affea4e2a 100644 --- a/src/calibre/gui2/convert/bulk.py +++ b/src/calibre/gui2/convert/bulk.py @@ -58,7 +58,8 @@ class BulkConfig(Config): output_path = 'dummy.'+output_format log = Log() log.outputs = [] - self.plumber = Plumber(input_path, output_path, log) + self.plumber = Plumber(input_path, output_path, log, + merge_plugin_recs=False) def widget_factory(cls): return cls(self.stack, self.plumber.get_option_by_name, From 965413b392ad160ada2c14be48ef48501c14b972 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Sep 2010 12:38:15 -0600 Subject: [PATCH 2/6] Cover generation: Scale logo to fit in available space --- src/calibre/utils/magick/draw.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index 17bf1c273a..82a0237b8d 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -165,12 +165,17 @@ def create_cover_page(top_lines, logo_path, width=590, height=750, top = height - lheight - 10 canvas.compose(vanity, left, top) - logo = Image() - logo.open(logo_path) - lwidth, lheight = logo.size - left = int(max(0, (width - lwidth)/2.)) - top = max(int((height - lheight)/2.), bottom+20) - canvas.compose(logo, left, top) + available = (width, int(top - bottom)-20) + if available[1] > 40: + logo = Image() + logo.open(logo_path) + lwidth, lheight = logo.size + scaled, lwidth, lheight = fit_image(lwidth, lheight, *available) + if scaled: + logo.size = (lwidth, lheight) + left = int(max(0, (width - lwidth)/2.)) + top = bottom+10 + canvas.compose(logo, left, top) return canvas.export(output_format) From f8541561f7960417ae7f6817b80aa8a7b77600b4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Sep 2010 13:04:14 -0600 Subject: [PATCH 3/6] Implement #6724 (Add series info to "Generate cover") --- src/calibre/ebooks/__init__.py | 8 ++++++++ src/calibre/ebooks/oeb/transforms/cover.py | 13 ++++++++----- src/calibre/gui2/dialogs/metadata_single.py | 14 +++++++++++--- src/calibre/web/feeds/news.py | 5 ++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/calibre/ebooks/__init__.py b/src/calibre/ebooks/__init__.py index 6596e9b1a2..624b277e61 100644 --- a/src/calibre/ebooks/__init__.py +++ b/src/calibre/ebooks/__init__.py @@ -138,3 +138,11 @@ def check_ebook_format(stream, current_guess): stream.seek(0) return ans +def calibre_cover(title, author_string, series_string=None, + output_format='jpg', title_size=46, author_size=36): + from calibre.utils.magick.draw import create_cover_page, TextLine + lines = [TextLine(title, title_size), TextLine(author_string, author_size)] + if series_string: + lines.append(TextLine(series_string, author_size)) + return create_cover_page(lines, I('library.png'), output_format='jpg') + diff --git a/src/calibre/ebooks/oeb/transforms/cover.py b/src/calibre/ebooks/oeb/transforms/cover.py index 83b7b5d3c1..59b42df68a 100644 --- a/src/calibre/ebooks/oeb/transforms/cover.py +++ b/src/calibre/ebooks/oeb/transforms/cover.py @@ -89,19 +89,22 @@ class CoverManager(object): ''' Create a generic cover for books that dont have a cover ''' - from calibre.ebooks.metadata import authors_to_string + from calibre.ebooks.metadata import authors_to_string, fmt_sidx if self.no_default_cover: return None self.log('Generating default cover') m = self.oeb.metadata title = unicode(m.title[0]) authors = [unicode(x) for x in m.creator if x.role == 'aut'] + series_string = None + if m.series and m.series_index: + series_string = _('Book %s of %s')%( + fmt_sidx(m.series_index[0], use_roman=True), m.series[0]) try: - from calibre.utils.magick.draw import create_cover_page, TextLine - lines = [TextLine(title, 44), TextLine(authors_to_string(authors), - 32)] - img_data = create_cover_page(lines, I('library.png')) + from calibre.ebooks import calibre_cover + img_data = calibre_cover(title, authors_to_string(authors), + series_string=series_string) id, href = self.oeb.manifest.generate('cover_image', 'cover_image.jpg') item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0], diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index 1393a50738..3d79b01c14 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -144,15 +144,23 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.cover_data = cover def generate_cover(self, *args): - from calibre.utils.magick.draw import create_cover_page, TextLine + from calibre.ebooks import calibre_cover + from calibre.ebooks.metadata import fmt_sidx + from calibre.gui2 import config title = unicode(self.title.text()).strip() author = unicode(self.authors.text()).strip() if not title or not author: return error_dialog(self, _('Specify title and author'), _('You must specify a title and author before generating ' 'a cover'), show=True) - lines = [TextLine(title, 44), TextLine(author, 32)] - self.cover_data = create_cover_page(lines, I('library.png')) + series = unicode(self.series.text()).strip() + series_string = None + if series: + series_string = _('Book %s of %s')%( + fmt_sidx(self.series_index.value(), + use_roman=config['use_roman_numerals_for_series_number']), series) + self.cover_data = calibre_cover(title, author, + series_string=series_string) pix = QPixmap() pix.loadFromData(self.cover_data) self.cover.setPixmap(pix) diff --git a/src/calibre/web/feeds/news.py b/src/calibre/web/feeds/news.py index 6df73487ed..9ba9583c73 100644 --- a/src/calibre/web/feeds/news.py +++ b/src/calibre/web/feeds/news.py @@ -1018,12 +1018,11 @@ class BasicNewsRecipe(Recipe): Create a generic cover for recipes that dont have a cover ''' try: - from calibre.utils.magick.draw import create_cover_page, TextLine + from calibre.ebooks import calibre_cover title = self.title if isinstance(self.title, unicode) else \ self.title.decode(preferred_encoding, 'replace') date = strftime(self.timefmt) - lines = [TextLine(title, 44), TextLine(date, 32)] - img_data = create_cover_page(lines, I('library.png'), output_format='jpg') + img_data = calibre_cover(title, date) cover_file.write(img_data) cover_file.flush() except: From 5b1d98aba9c6299f950c3561d853c96fd522530e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Sep 2010 16:59:59 -0600 Subject: [PATCH 4/6] Hide visible menus before clearing toolbar. Fixes #6706 (Clicking the Connect/Share button during startup crashes Calibre 0.7.17) --- src/calibre/gui2/layout.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 68f093da95..58d5267c8e 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -215,6 +215,7 @@ class ToolBar(QToolBar): # {{{ self.location_manager.locations_changed.connect(self.build_bar) donate.setAutoRaise(True) donate.setCursor(Qt.PointingHandCursor) + self.added_actions = [] self.build_bar() self.preferred_width = self.sizeHint().width() @@ -237,7 +238,13 @@ class ToolBar(QToolBar): # {{{ actions = '-device' if showing_device else '' actions = gprefs['action-layout-toolbar'+actions] + for ac in self.added_actions: + m = ac.menu() + if m is not None: + m.setVisible(False) + self.clear() + self.added_actions = [] for what in actions: if what is None: @@ -245,6 +252,7 @@ class ToolBar(QToolBar): # {{{ elif what == 'Location Manager': for ac in self.location_manager.available_actions: self.addAction(ac) + self.added_actions.append(ac) self.setup_tool_button(ac, QToolButton.MenuButtonPopup) elif what == 'Donate': self.d_widget = QWidget() @@ -255,6 +263,7 @@ class ToolBar(QToolBar): # {{{ elif what in self.gui.iactions: action = self.gui.iactions[what] self.addAction(action.qaction) + self.added_actions.append(action.qaction) self.setup_tool_button(action.qaction, action.popup_type) def setup_tool_button(self, ac, menu_mode=None): From 31db5a16ddc047c0535c079da40af07806e496d4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Sep 2010 17:18:47 -0600 Subject: [PATCH 5/6] Implement #6450 (Bookmarks in Calibre's Viewer) --- src/calibre/gui2/viewer/main.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index c8f1f62856..79f4c29998 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -173,6 +173,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.pending_anchor = None self.pending_reference = None self.pending_bookmark = None + self.existing_bookmarks= [] self.selected_text = None self.read_settings() self.dictionary_box.hide() @@ -415,15 +416,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2) self.set_page_number(frac) - def bookmark(self, *args): - title, ok = QInputDialog.getText(self, _('Add bookmark'), _('Enter title for bookmark:')) - title = unicode(title).strip() - if ok and title: - pos = self.view.bookmark() - bookmark = '%d#%s'%(self.current_index, pos) - self.iterator.add_bookmark((title, bookmark)) - self.set_bookmarks(self.iterator.bookmarks) - def find(self, text, repeat=False, backwards=False): if not text: @@ -539,15 +531,34 @@ class EbookViewer(MainWindow, Ui_EbookViewer): getattr(self, o).setEnabled(False) self.setCursor(Qt.BusyCursor) + def bookmark(self, *args): + num = 1 + bm = None + while True: + bm = _('Bookmark #%d')%num + if bm not in self.existing_bookmarks: + break + num += 1 + title, ok = QInputDialog.getText(self, _('Add bookmark'), + _('Enter title for bookmark:'), text=bm) + title = unicode(title).strip() + if ok and title: + pos = self.view.bookmark() + bookmark = '%d#%s'%(self.current_index, pos) + self.iterator.add_bookmark((title, bookmark)) + self.set_bookmarks(self.iterator.bookmarks) + def set_bookmarks(self, bookmarks): self.bookmarks_menu.clear() self.bookmarks_menu.addAction(_("Manage Bookmarks"), self.manage_bookmarks) self.bookmarks_menu.addSeparator() current_page = None + self.existing_bookmarks = [] for bm in bookmarks: if bm[0] == 'calibre_current_page_bookmark': current_page = bm else: + self.existing_bookmarks.append(bm[0]) self.bookmarks_menu.addAction(bm[0], partial(self.goto_bookmark, bm)) return current_page From 3c257cdb56f84040511c7e07b69a3eb94b69b7ef Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Sep 2010 20:24:30 -0600 Subject: [PATCH 6/6] Extract fb2 files from zip container when adding to calibre. Can be disables by disabling the Archive Extract file type plugin. Fixes #6739 (Adding a zip file that contains an fb2 file) --- resources/images/swap.png | Bin 161 -> 13638 bytes src/calibre/ebooks/metadata/archive.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/images/swap.png b/resources/images/swap.png index 60b8803d95b77181b8cd84107acc3b6553dc2df9..e5aeb60e223db413010b0539566c2cfaff0c89bd 100644 GIT binary patch literal 13638 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