diff --git a/resources/images/swap.png b/resources/images/swap.png index 60b8803d95..e5aeb60e22 100644 Binary files a/resources/images/swap.png and b/resources/images/swap.png differ 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/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/metadata/archive.py b/src/calibre/ebooks/metadata/archive.py index 624c2ad5e5..f5982406ea 100644 --- a/src/calibre/ebooks/metadata/archive.py +++ b/src/calibre/ebooks/metadata/archive.py @@ -70,7 +70,7 @@ class ArchiveExtract(FileTypePlugin): fname = fnames[0] ext = os.path.splitext(fname)[1][1:] if ext.lower() not in ('lit', 'epub', 'mobi', 'prc', 'rtf', 'pdf', - 'mp3', 'pdb', 'azw', 'azw1'): + 'mp3', 'pdb', 'azw', 'azw1', 'fb2'): return archive of = self.temporary_file('_archive_extract.'+ext) 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/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, 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/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): 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 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) 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: