From c33c5cbf58f116f3e52bf2c37831c0f5e5d0da8e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 8 Aug 2011 12:47:16 -0600 Subject: [PATCH 01/16] Fix #807879 ("Series" undistinguished in singular/plural) --- src/calibre/gui2/library/models.py | 2 +- src/calibre/library/save_to_disk.py | 4 +- src/calibre/translations/calibre.pot | 712 +++++++++++++++------------ 3 files changed, 389 insertions(+), 329 deletions(-) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 0937f0bb12..4d11784aea 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -62,7 +62,7 @@ class BooksModel(QAbstractTableModel): # {{{ 'rating' : _('Rating'), 'publisher' : _("Publisher"), 'tags' : _("Tags"), - 'series' : _("Series"), + 'series' : ngettext("Series", 'Series', 1), 'last_modified' : _('Modified'), } diff --git a/src/calibre/library/save_to_disk.py b/src/calibre/library/save_to_disk.py index 2c723e0f7d..cacb607d56 100644 --- a/src/calibre/library/save_to_disk.py +++ b/src/calibre/library/save_to_disk.py @@ -296,8 +296,8 @@ def do_save_book_to_disk(id_, mi, cover, plugboards, replace_whitespace=opts.replace_whitespace, safe_format=False) except Exception, e: raise ValueError(_('Failed to calculate path for ' - 'save to disk. Template: %s\n' - 'Error: %s'%(opts.template, e))) + 'save to disk. Template: %(templ)s\n' + 'Error: %(err)s')%dict(templ=opts.template, err=e)) if opts.single_dir: components = components[-1:] if not components: diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 17adb883f0..a42f0833e7 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.8.13\n" -"POT-Creation-Date: 2011-08-05 09:47+MDT\n" -"PO-Revision-Date: 2011-08-05 09:47+MDT\n" +"POT-Creation-Date: 2011-08-08 12:45+MDT\n" +"PO-Revision-Date: 2011-08-08 12:45+MDT\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -62,8 +62,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:36 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:64 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:66 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:124 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:126 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:120 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/meta.py:122 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1080 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1190 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/pdb.py:41 @@ -133,9 +133,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:315 #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:376 #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:384 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:155 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:376 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:379 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:158 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:377 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:380 #: /home/kovid/work/calibre/src/calibre/gui2/add.py:161 #: /home/kovid/work/calibre/src/calibre/gui2/add.py:168 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:555 @@ -176,9 +176,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/database2.py:554 #: /home/kovid/work/calibre/src/calibre/library/database2.py:2006 #: /home/kovid/work/calibre/src/calibre/library/database2.py:2153 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3170 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3172 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3305 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3171 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3173 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3306 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:225 #: /home/kovid/work/calibre/src/calibre/library/server/content.py:226 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:243 @@ -204,8 +204,8 @@ msgid "Customize" msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:156 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:51 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:56 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:52 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:57 msgid "Cannot configure" msgstr "" @@ -230,8 +230,8 @@ msgid "User Interface Action" msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:557 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:18 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:25 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:20 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:28 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:197 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:287 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:309 @@ -832,10 +832,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/db/cache.py:131 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:636 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:66 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:564 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:563 #: /home/kovid/work/calibre/src/calibre/library/database2.py:972 -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:758 -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:770 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:806 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:818 msgid "Yes" msgstr "" @@ -973,7 +973,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1141 #: /home/kovid/work/calibre/src/calibre/library/database2.py:330 #: /home/kovid/work/calibre/src/calibre/library/database2.py:343 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3031 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3032 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:171 msgid "News" msgstr "" @@ -1152,12 +1152,12 @@ msgstr "" msgid "Communicate with the Sigmatek eBook reader." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/folder_device/driver.py:16 -#: /home/kovid/work/calibre/src/calibre/devices/folder_device/driver.py:32 +#: /home/kovid/work/calibre/src/calibre/devices/folder_device/driver.py:17 +#: /home/kovid/work/calibre/src/calibre/devices/folder_device/driver.py:33 msgid "Use an arbitrary folder as a device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/folder_device/driver.py:28 +#: /home/kovid/work/calibre/src/calibre/devices/folder_device/driver.py:29 #: /home/kovid/work/calibre/src/calibre/devices/interface.py:14 msgid "Device Interface" msgstr "" @@ -1290,7 +1290,7 @@ msgid "Create tags for automatic management" msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:543 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:387 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:390 msgid "Not Implemented" msgstr "" @@ -2587,7 +2587,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:636 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:66 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:564 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:563 msgid "No" msgstr "" @@ -3507,7 +3507,7 @@ msgstr "" msgid "tag browser categories not to display" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:490 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:492 msgid "Choose Files" msgstr "" @@ -3576,106 +3576,123 @@ msgstr "" msgid "Add books from a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:57 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:58 msgid "Add books from directories, including sub-directories (One book per directory, assumes every ebook file is the same book in a different format)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:61 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:62 msgid "Add books from directories, including sub directories (Multiple books per directory, assumes every ebook file is a different book)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:65 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:67 msgid "Add Empty book. (Book entry with no formats)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:66 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:68 msgid "Shift+Ctrl+E" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:67 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:69 msgid "Add from ISBN" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:69 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:71 msgid "Add files to selected book records" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:70 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:72 msgid "Shift+A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:89 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/annotate.py:69 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:89 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:74 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:158 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:222 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:259 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:91 +msgid "No books selected" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:88 +msgid "Cannot add files as no books are selected" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:92 msgid "Are you sure" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:93 #, python-format msgid "Are you sure you want to add the same files to all %d books? If the formatalready exists for a book, it will be replaced." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:96 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:99 msgid "Select book files" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:167 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:170 msgid "Adding" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:168 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:171 msgid "Creating book records from ISBNs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:267 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:316 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:319 msgid "Uploading books to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:287 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:290 msgid "Supported books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:290 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:293 msgid "Select books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:331 msgid "Merged some books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:329 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:332 msgid "The following duplicate books were found and incoming book formats were processed and merged into your Calibre database according to your automerge settings:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:348 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:351 msgid "Failed to read metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:349 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:352 msgid "Failed to read metadata from the following" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:370 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:375 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:394 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:373 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:378 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:397 msgid "Add to library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:375 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:132 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:84 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:103 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:112 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:378 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:106 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:115 #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:30 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:139 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:185 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:183 msgid "No book selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:388 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:391 msgid "The following books are virtual and cannot be added to the calibre library:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:394 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:397 msgid "No book files found" msgstr "" @@ -3710,18 +3727,6 @@ msgstr "" msgid "User annotations generated from main library only" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/annotate.py:69 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:33 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:87 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:137 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:73 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:157 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:221 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:258 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:90 -msgid "No books selected" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/actions/annotate.py:70 msgid "No books selected to fetch annotations from" msgstr "" @@ -3756,7 +3761,7 @@ msgid "Location %(dl)d • %(typ)s
" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:20 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:35 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:37 msgid "Create a catalog of the books in your calibre library" msgstr "" @@ -3960,7 +3965,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:408 #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:413 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:178 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:99 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:100 #: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:886 msgid "Not allowed" msgstr "" @@ -3981,25 +3986,25 @@ msgstr "" msgid "Convert books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:29 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:30 msgid "Convert individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:31 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:33 msgid "Bulk convert" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:86 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:562 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:88 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:569 msgid "Cannot convert" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:115 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:117 #, python-format msgid "Starting conversion of %d book(s)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:175 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:177 msgid "Empty output file, probably the conversion process crashed" msgstr "" @@ -4091,88 +4096,88 @@ msgstr "" msgid "Remove selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:94 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:95 msgid "Remove files of a specific format from selected books.." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:97 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:98 msgid "Remove all formats from selected books, except..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:100 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:101 msgid "Remove all formats from selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:103 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:104 msgid "Remove covers from selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:106 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:108 msgid "Remove matching books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:129 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:131 msgid "Cannot delete" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:142 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:144 msgid "Choose formats to be deleted" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:160 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:162 msgid "Choose formats not to be deleted.

Note that this will never remove all formats from a book." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:186 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:188 msgid "All formats for the selected books will be deleted from your library.
The book metadata will be kept. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:206 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:208 msgid "Cannot delete books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:207 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:209 msgid "No device is connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:219 msgid "Main memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:218 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:220 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:516 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:525 msgid "Storage Card A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:219 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:221 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:518 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:527 msgid "Storage Card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:224 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:226 msgid "No books to delete" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:225 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:227 msgid "None of the selected books are on the device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:242 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:333 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:244 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:335 msgid "Deleting books from device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:288 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:290 msgid "Some of the selected books are on the attached device. Where do you want the selected files deleted from?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:300 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:302 msgid "The selected books will be permanently deleted and the files removed from your calibre library. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:325 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:327 msgid "The selected books will be permanently deleted from your device. Are you sure?" msgstr "" @@ -4189,49 +4194,49 @@ msgid "Connect to Bambook" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:56 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:64 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:73 msgid "Start Content Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:66 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:75 msgid "Stop Content Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:77 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:96 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:86 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:105 msgid "Email to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:81 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:90 msgid "Email to and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:99 msgid "(delete from library)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:105 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:114 msgid "Setup email based sharing of books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:132 msgid "D" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:132 msgid "Send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:141 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:150 msgid "Connect/share" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:178 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:187 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:79 msgid "Stopping" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:179 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:188 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:80 msgid "Stopping server, this could take upto a minute, please wait..." msgstr "" @@ -4252,131 +4257,131 @@ msgstr "" msgid "Edit metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:30 -msgid "Merge book records" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:31 -msgid "M" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:32 msgid "Edit metadata individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:36 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:35 msgid "Edit metadata in bulk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:39 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:38 msgid "Download metadata and covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:44 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:45 msgid "Merge into first selected book - delete others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:47 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:48 msgid "Merge into first selected book - keep others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:51 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:52 msgid "Merge only formats into first selected book - delete others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:72 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:57 +msgid "Merge book records" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:58 +msgid "M" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:73 msgid "Cannot download metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:82 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:83 msgid "Failed to download metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:88 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:89 #: /home/kovid/work/calibre/src/calibre/gui2/dnd.py:84 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:472 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:720 msgid "Download failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:89 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:90 #, python-format msgid "Failed to download metadata or covers for any of the %d book(s)." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:93 msgid "Metadata download completed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:94 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:95 #, python-format msgid "Finished downloading metadata for %d book(s). Proceed with updating the metadata in your library?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:101 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:102 #, python-format msgid "Could not download metadata and/or covers for %d of the books. Click \"Show details\" to see which books." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:108 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:109 msgid "Download complete" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:108 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:109 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:781 msgid "Download log" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:138 msgid "Some books changed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:139 msgid "The metadata for some books in your library has changed since you started the download. If you proceed, some of those changes may be overwritten. Click \"Show details\" to see the list of changed books. Do you want to proceed?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:156 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:220 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:157 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:221 msgid "Cannot edit metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:257 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:260 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:258 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:261 msgid "Cannot merge books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:261 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:262 msgid "At least two books must be selected for merging" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:264 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:265 msgid "You are about to merge more than 5 books. Are you sure you want to proceed?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:273 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:274 #, python-format msgid "Book formats and metadata from the selected books will be added to the first selected book (%s). ISBN will not be merged.

The second and subsequently selected books will not be deleted or changed.

Please confirm you want to proceed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:285 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:286 #, python-format msgid "Book formats from the selected books will be merged into the first selected book (%s). Metadata in the first selected book will not be changed. Author, Title, ISBN and all other metadata will not be merged.

After merger the second and subsequently selected books, with any metadata they have will be deleted.

All book formats of the first selected book will be kept and any duplicate formats in the second and subsequently selected books will be permanently deleted from your calibre library.

Are you sure you want to proceed?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:301 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:302 #, python-format msgid "Book formats and metadata from the selected books will be merged into the first selected book (%s). ISBN will not be merged.

After merger the second and subsequently selected books will be deleted.

All book formats of the first selected book will be kept and any duplicate formats in the second and subsequently selected books will be permanently deleted from your calibre library.

Are you sure you want to proceed?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:471 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:472 msgid "Applying changed metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:544 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:545 msgid "Some failures" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:545 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:546 msgid "Failed to apply updated metadata for some books in your library. Click \"Show Details\" to see details." msgstr "" @@ -4420,7 +4425,7 @@ msgid "Move to next highlighted match" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/next_match.py:13 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:415 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:421 msgid "N" msgstr "" @@ -4453,32 +4458,32 @@ msgstr "" msgid "Plugin Updater" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:18 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:20 msgid "Ctrl+P" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:20 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:22 msgid "Change calibre behavior" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:26 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:29 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:208 msgid "Run welcome wizard" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:29 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:31 msgid "Get plugins to enhance calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:35 msgid "Restart in debug mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:52 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:53 msgid "Cannot configure while there are running jobs." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:57 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:58 msgid "Cannot configure before calibre is restarted." msgstr "" @@ -4503,48 +4508,48 @@ msgstr "" msgid "Save to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:47 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:48 msgid "Save to disk in a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:49 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:67 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:68 #, python-format msgid "Save only %s format to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:53 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:70 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:71 #, python-format msgid "Save only %s format to disk in a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:89 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:90 msgid "Cannot save to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:93 msgid "Choose destination directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:100 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:101 msgid "You are trying to save files into the calibre library. This can cause corruption of your library. Save to disk is meant to export files from your calibre library elsewhere." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:132 msgid "Error while saving" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:133 msgid "There was an error while saving." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:142 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:143 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:140 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:141 msgid "Could not save some books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:144 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:142 msgid "Click the show details button to see which ones." msgstr "" @@ -4629,53 +4634,58 @@ msgstr "" msgid "Search for ebooks" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:28 +msgid "author" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:28 +msgid "title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:29 +msgid "book" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:32 -msgid "Search for this author" +#, python-format +msgid "Search for this %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:33 -msgid "Search for this title" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:34 -msgid "Search for this book" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:36 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:35 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/search_ui.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/store/search_ui.py:110 msgid "Stores" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:45 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:38 #: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/chooser_dialog.py:18 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/search.py:285 msgid "Choose stores" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:84 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:103 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:112 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:106 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:115 msgid "Cannot search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:134 msgid "Calibre helps you find the ebooks you want by searching the websites of various commercial and public domain book sources for you." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:138 msgid "Using the integrated search you can easily find which store has the book you are looking for, at the best price. You also get DRM status and other useful information." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:142 msgid "All transactions (paid or otherwise) are handled between you and the book seller. Calibre is not part of this process and any issues related to a purchase should be directed to the website you are buying from. Be sure to double check that any books you get will work with your e-book reader, especially if the book you are buying has DRM." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:149 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:152 msgid "Show this message again" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/store.py:153 msgid "About Get Books" msgstr "" @@ -4701,15 +4711,15 @@ msgstr "" msgid "No ePub available. First convert the book to ePub." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:36 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:37 msgid "V" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:36 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:37 msgid "View" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:48 msgid "View specific format" msgstr "" @@ -4717,53 +4727,53 @@ msgstr "" msgid "Read a random book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:55 msgid "Clear recently viewed list" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:139 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:219 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:226 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:224 msgid "Cannot view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:152 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:166 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:164 msgid "Format unavailable" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:153 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:151 msgid "Selected books have no formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:155 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:153 #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:128 msgid "Choose the format to view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:167 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:165 #, python-format msgid "Not all the selected books were available in the %s format. You should convert them first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:172 msgid "Multiple Books Selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:175 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:173 #, python-format msgid "You are attempting to open %d books. Opening too many books at once can be slow and have a negative effect on the responsiveness of your computer. Once started the process cannot be stopped until complete. Do you wish to continue?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:182 msgid "Cannot open folder" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:220 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:218 msgid "This book no longer exists in your library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:227 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:225 #, python-format msgid "%s has no available formats." msgstr "" @@ -5117,7 +5127,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc_ui.py:65 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard_ui.py:113 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins_ui.py:105 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:56 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/saving_ui.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:109 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/sending_ui.py:68 @@ -6663,11 +6673,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:115 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:152 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:186 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:303 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:568 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:609 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:632 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:683 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:567 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:608 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:631 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:682 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:307 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:312 #: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:128 @@ -6680,23 +6689,23 @@ msgid "Undefined" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:129 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:640 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:639 msgid "star(s)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:130 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:641 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:640 msgid "Unrated" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:173 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:670 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:669 #, python-format msgid "Set '%s' to today" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:175 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:672 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:671 #, python-format msgid "Clear '%s'" msgstr "" @@ -6705,39 +6714,39 @@ msgstr "" msgid " index:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:368 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:367 msgid "The enumeration \"{0}\" contains an invalid value that will be set to the default" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:523 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:522 msgid "Apply changes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:716 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:715 msgid "Remove series" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:719 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:718 msgid "Automatically number books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:722 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:721 msgid "Force numbers to start with " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:794 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:793 msgid "The enumeration \"{0}\" contains invalid values that will not appear in the list" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:838 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:837 msgid "Remove all tags" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:858 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:857 msgid "tags to add" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:865 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:864 msgid "tags to remove" msgstr "" @@ -6932,16 +6941,16 @@ msgid "You have enabled the {0} formats for your {1}. The {1} may not sup msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:148 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:464 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:470 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:275 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:61 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:70 msgid "Invalid template" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:149 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:465 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:471 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:276 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:62 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:71 #, python-format msgid "The template %s is invalid:" msgstr "" @@ -9113,7 +9122,8 @@ msgid "Open Template Editor" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_line_editor.py:41 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:451 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:457 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:48 msgid "Edit template" msgstr "" @@ -9566,9 +9576,6 @@ msgid "Book Details" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:221 -msgid "Alt+D" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/init.py:231 msgid "Shift+Alt+D" msgstr "" @@ -9677,35 +9684,36 @@ msgstr "" msgid "available" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:181 -msgid "Shift+Ctrl+F" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:189 msgid "Advanced search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:189 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:184 +msgid "Shift+Ctrl+F" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:194 msgid "

Search the list of books by title, author, publisher, tags, comments, etc.

Words separated by spaces are ANDed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:195 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:200 msgid "&Go!" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:201 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:206 msgid "Do Quick Search (you can also press the Enter key)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:207 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:212 msgid "Reset Quick Search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:223 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:228 msgid "Copy current search text (instead of search name)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:415 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:421 msgid "Y" msgstr "" @@ -11878,34 +11886,38 @@ msgstr "" msgid "&Load plugin from file" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:34 msgid "Any custom field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:34 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:35 msgid "The lookup name of any custom field (these names begin with \"#\")." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:57 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:66 msgid "Constant template" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:58 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:67 msgid "The template contains no {fields}, so all books will have the same name. Is this OK?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:47 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:57 msgid "Save &template" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:48 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:58 msgid "By adjusting the template below, you can control what folders the files are saved in and what filenames they are given. You can use the / character to indicate sub-folders. Available metadata variables are described below. If a particular book does not have some metadata, the variable will be replaced by the empty string." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:49 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:59 msgid "Available variables:" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:60 +msgid "Template Editor" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/preferences/saving_ui.py:68 msgid "Here you can control how calibre will save your books when you click the Save to Disk button:" msgstr "" @@ -12082,7 +12094,7 @@ msgid "Here you can control how calibre will save your books when you click the msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:70 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:424 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:431 msgid "Failed to start content server" msgstr "" @@ -12434,35 +12446,39 @@ msgstr "" msgid "Search (For Advanced Search click the button to the left)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:390 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:383 +msgid "Start search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:393 msgid "Enable or disable search highlighting." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:445 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:448 msgid "Saved Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:447 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:450 msgid "Choose saved search or enter name for new saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:453 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:456 msgid "Save current search under the name shown in the box. Press and hold for a pop-up options menu." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:458 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:461 msgid "Create saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:462 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:465 msgid "Delete saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:466 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:469 msgid "Manage saved searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:476 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:479 msgid "*Current search" msgstr "" @@ -13229,55 +13245,63 @@ msgstr "" msgid "The following books have already been converted to %s format. Do you wish to reconvert them?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:196 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:198 msgid "&Donate to support calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:232 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:234 msgid "&Restore" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:237 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:239 msgid "&Eject connected device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:347 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:243 +msgid "Quit calibre" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:256 +msgid "Clear the current search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:354 msgid "Debug mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:348 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:355 #, python-format msgid "You have started calibre in debug mode. After you quit calibre, the debug log will be available in the file: %s

The log will be displayed automatically." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:550 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:557 msgid "Conversion Error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:573 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:580 msgid "Recipe Disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:589 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:596 msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:623 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:630 msgid "There are active jobs. Are you sure you want to quit?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:626 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:633 msgid "" " is communicating with the device!
\n" " Quitting may cause corruption on the device.
\n" " Are you sure you want to quit?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:630 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:637 msgid "Active jobs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:698 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:705 msgid "will keep running in the system tray. To close it, choose Quit in the context menu of the system tray." msgstr "" @@ -14142,7 +14166,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/caches.py:568 #: /home/kovid/work/calibre/src/calibre/library/caches.py:582 #: /home/kovid/work/calibre/src/calibre/library/caches.py:592 -#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:219 +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:222 msgid "yes" msgstr "" @@ -14150,7 +14174,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/library/caches.py:567 #: /home/kovid/work/calibre/src/calibre/library/caches.py:579 #: /home/kovid/work/calibre/src/calibre/library/caches.py:589 -#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:219 +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:222 msgid "no" msgstr "" @@ -14980,17 +15004,17 @@ msgstr "" msgid "%(tt)sAverage rating is %(rating)3.1f" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3331 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3332 #, python-format msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3360 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3361 #, python-format msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:3377 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:3378 msgid "Compacting database" msgstr "" @@ -15118,8 +15142,24 @@ msgstr "" msgid "Replace whitespace with underscores." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:382 -#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:415 +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:125 +msgid "Save into a single directory, ignoring the template directory structure" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:298 +#, python-format +msgid "" +"Failed to calculate path for save to disk. Template: %(templ)s\n" +"Error: %(err)s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:304 +#, python-format +msgid "Template evaluation resulted in no path components. Template: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:398 +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:431 msgid "Requested formats not available" msgstr "" @@ -15499,7 +15539,7 @@ msgstr "" msgid "%s: unknown function" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:348 +#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:357 msgid "No such variable " msgstr "" @@ -15520,206 +15560,226 @@ msgid "strcat(a, b, ...) -- can take any number of arguments. Returns a string f msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:143 +msgid "strlen(a) -- Returns the length of the string passed as the argument" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:156 msgid "add(x, y) -- returns x + y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:154 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:167 msgid "subtract(x, y) -- returns x - y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:165 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:178 msgid "multiply(x, y) -- returns x * y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:176 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:189 msgid "divide(x, y) -- returns x / y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:188 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:201 msgid "template(x) -- evaluates x as a template. The evaluation is done in its own context, meaning that variables are not shared between the caller and the template evaluation. Because the { and } characters are special, you must use [[ for the { character and ]] for the } character; they are converted automatically. For example, template('[[title_sort]]') will evaluate the template {title_sort} and return its value." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:204 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:217 msgid "eval(template) -- evaluates the template, passing the local variables (those 'assign'ed to) instead of the book metadata. This permits using the template processor to construct complex results from local variables." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:218 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:231 msgid "assign(id, val) -- assigns val to id, then returns val. id must be an identifier, not an expression" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:229 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:242 msgid "print(a, b, ...) -- prints the arguments to standard output. Unless you start calibre from the command line (calibre-debug -g), the output will go to a black hole." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:241 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:254 msgid "field(name) -- returns the metadata field named by name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:250 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:263 msgid "raw_field(name) -- returns the metadata field named by name without applying any formatting." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:260 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:273 msgid "substr(str, start, end) -- returns the start'th through the end'th characters of str. The first character in str is the zero'th character. If end is negative, then it indicates that many characters counting from the right. If end is zero, then it indicates the last character. For example, substr('12345', 1, 0) returns '2345', and substr('12345', 1, -1) returns '234'." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:274 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:287 msgid "lookup(val, pattern, field, pattern, field, ..., else_field) -- like switch, except the arguments are field (metadata) names, not text. The value of the appropriate field will be fetched and used. Note that because composite columns are fields, you can use this function in one composite field to use the value of some other composite field. This is extremely useful when constructing variable save paths" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:289 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:302 msgid "lookup requires either 2 or an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:302 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:315 msgid "test(val, text if not empty, text if empty) -- return `text if not empty` if the field is not empty, otherwise return `text if empty`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:315 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:328 msgid "contains(val, pattern, text if match, text if not match) -- checks if field contains matches for the regular expression `pattern`. Returns `text if match` if matches are found, otherwise it returns `text if no match`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:331 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:344 msgid "switch(val, pattern, value, pattern, value, ..., else_value) -- for each `pattern, value` pair, checks if the field matches the regular expression `pattern` and if so, returns that `value`. If no pattern matches, then else_value is returned. You can have as many `pattern, value` pairs as you want" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:339 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:352 msgid "switch requires an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:352 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:365 +msgid "strcat_max(max, string1, prefix2, string2, ...) -- Returns a string formed by concatenating the arguments. The returned value is initialized to string1. `Prefix, string` pairs are added to the end of the value as long as the resulting string length is less than `max`. String1 is returned even if string1 is longer than max. You can pass as many `prefix, string` pairs as you wish." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:375 +msgid "strcat_max requires 2 or more arguments" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:377 +msgid "strcat_max requires an even number of arguments" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:381 +msgid "first argument to strcat_max must be an integer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:399 msgid "in_list(val, separator, pattern, found_val, not_found_val) -- treat val as a list of items separated by separator, comparing the pattern against each value in the list. If the pattern matches a value, return found_val, otherwise return not_found_val." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:370 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:417 msgid "str_in_list(val, separator, string, found_val, not_found_val) -- treat val as a list of items separated by separator, comparing the string against each value in the list. If the string matches a value, return found_val, otherwise return not_found_val. If the string contains separators, then it is also treated as a list and each value is checked." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:391 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:438 msgid "identifier_in_list(val, id, found_val, not_found_val) -- treat val as a list of identifiers separated by commas, comparing the string against each value in the list. An identifier has the format \"identifier:value\". The id parameter should be either \"id\" or \"id:regexp\". The first case matches if there is any identifier with that id. The second case matches if the regexp matches the identifier's value. If there is a match, return found_val, otherwise return not_found_val." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:417 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:464 msgid "re(val, pattern, replacement) -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of calibre, these are python-compatible regular expressions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:429 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:476 msgid "swap_around_comma(val) -- given a value of the form \"B, A\", return \"A B\". This is most useful for converting names in LN, FN format to FN LN. If there is no comma, the function returns val unchanged" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:441 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:488 msgid "ifempty(val, text if empty) -- return val if val is not empty, otherwise return `text if empty`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:454 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:501 msgid "shorten(val, left chars, middle text, right chars) -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use {title:shorten(9,-,5)}, the result will be `Ancient E-nhoe`. If the field's length is less than left chars + right chars + the length of `middle text`, then the field will be used intact. For example, the title `The Dome` would not be changed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:480 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:527 msgid "count(val, separator) -- interprets the value as a list of items separated by `separator`, returning the number of items in the list. Most lists use a comma as the separator, but authors uses an ampersand. Examples: {tags:count(,)}, {authors:count(&)}" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:492 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:539 msgid "list_item(val, index, separator) -- interpret the value as a list of items separated by `separator`, returning the `index`th item. The first item is number zero. The last item can be returned using `list_item(-1,separator)`. If the item is not in the list, then the empty value is returned. The separator has the same meaning as in the count function." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:513 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:560 msgid "select(val, key) -- interpret the value as a comma-separated list of items, with the items being \"id:value\". Find the pair with the id equal to key, and return the corresponding value." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:531 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:578 msgid "formats_modtimes(date_format) -- return a comma-separated list of colon_separated items representing modification times for the formats of a book. The date_format parameter specifies how the date is to be formatted. See the date_format function for details. You can use the select function to get the mod time for a specific format. Note that format names are always uppercase, as in EPUB." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:550 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:597 msgid "formats_sizes() -- return a comma-separated list of colon_separated items representing sizes in bytes of the formats of a book. You can use the select function to get the size for a specific format. Note that format names are always uppercase, as in EPUB." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:566 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:613 msgid "human_readable(v) -- return a string representing the number v in KB, MB, GB, etc." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:580 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:627 msgid "format_number(v, template) -- format the number v using a python formatting template such as \"{0:5.2f}\" or \"{0:,d}\" or \"${0:5,.2f}\". The field_name part of the template must be a 0 (zero) (the \"{0:\" in the above examples). See the template language and python documentation for more examples. Returns the empty string if formatting fails." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:605 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:652 msgid "sublist(val, start_index, end_index, separator) -- interpret the value as a list of items separated by `separator`, returning a new list made from the `start_index` to the `end_index` item. The first item is number zero. If an index is negative, then it counts from the end of the list. As a special case, an end_index of zero is assumed to be the length of the list. Examples using basic template mode and assuming that the tags column (which is comma-separated) contains \"A, B, C\": {tags:sublist(0,1,\\,)} returns \"A\". {tags:sublist(-1,0,\\,)} returns \"C\". {tags:sublist(0,-1,\\,)} returns \"A, B\"." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:636 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:684 msgid "subitems(val, start_index, end_index) -- This function is used to break apart lists of items such as genres. It interprets the value as a comma-separated list of items, where each item is a period-separated list. Returns a new list made by first finding all the period-separated items, then for each such item extracting the start_index` to the `end_index` components, then combining the results back together. The first component in a period-separated list has an index of zero. If an index is negative, then it counts from the end of the list. As a special case, an end_index of zero is assumed to be the length of the list. Example using basic template mode and assuming a #genre value of \"A.B.C\": {#genre:subitems(0,1)} returns \"A\". {#genre:subitems(0,2)} returns \"A.B\". {#genre:subitems(1,0)} returns \"B.C\". Assuming a #genre value of \"A.B.C, D.E.F\", {#genre:subitems(0,1)} returns \"A, D\". {#genre:subitems(0,2)} returns \"A.B, D.E\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:674 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:722 msgid "format_date(val, format_string) -- format the value, which must be a date, using the format_string, returning a string. The formatting codes are: d : the day as number without a leading zero (1 to 31) dd : the day as number with a leading zero (01 to 31) ddd : the abbreviated localized day name (e.g. \"Mon\" to \"Sun\"). dddd : the long localized day name (e.g. \"Monday\" to \"Sunday\"). M : the month as number without a leading zero (1 to 12). MM : the month as number with a leading zero (01 to 12) MMM : the abbreviated localized month name (e.g. \"Jan\" to \"Dec\"). MMMM : the long localized month name (e.g. \"January\" to \"December\"). yy : the year as two digit number (00 to 99). yyyy : the year as four digit number. iso : the date with time and timezone. Must be the only format present" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:703 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:751 msgid "uppercase(val) -- return value of the field in upper case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:712 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:760 msgid "lowercase(val) -- return value of the field in lower case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:721 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:769 msgid "titlecase(val) -- return value of the field in title case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:730 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:778 msgid "capitalize(val) -- return value of the field capitalized" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:739 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:787 msgid "booksize() -- return value of the size field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:753 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:801 msgid "ondevice() -- return Yes if ondevice is set, otherwise return the empty string" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:765 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:813 msgid "has_cover() -- return Yes if the book has a cover, otherwise return the empty string" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:777 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:825 msgid "first_non_empty(value, value, ...) -- returns the first value that is not empty. If all values are empty, then the empty value is returned.You can have as many values as you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:794 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:842 msgid "and(value, value, ...) -- returns the string \"1\" if all values are not empty, otherwise returns the empty string. This function works well with test or first_non_empty. You can have as many values as you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:811 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:859 msgid "or(value, value, ...) -- returns the string \"1\" if any value is not empty, otherwise returns the empty string. This function works well with test or first_non_empty. You can have as many values as you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:828 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:876 msgid "not(value) -- returns the string \"1\" if the value is empty, otherwise returns the empty string. This function works well with test or first_non_empty. You can have as many values as you want." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:840 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:888 msgid "list_union(list1, list2, separator) -- return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive compare. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:865 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:913 msgid "list_difference(list1, list2, separator) -- return a list made by removing from list1 any item found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:884 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:932 msgid "list_intersection(list1, list2, separator) -- return a list made by removing from list1 any item not found in list2, using a case-insensitive compare. The items in list1 and list2 are separated by separator, as are the items in the returned list." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:903 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:951 msgid "list_sort(list, direction, separator) -- return list sorted using a case-insensitive sort. If direction is zero, the list is sorted ascending, otherwise descending. The list items are separated by separator, as are the items in the returned list." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:916 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:964 msgid "today() -- return a date string for today. This value is designed for use in format_date or days_between, but can be manipulated like any other string. The date is in ISO format." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:927 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:975 msgid "days_between(date1, date2) -- return the number of days between date1 and date2. The number is positive if date1 is greater than date2, otherwise negative. If either date1 or date2 are not dates, the function returns the empty string." msgstr "" From 727e2805ff4f0f2e4959040946c305b725ab7f96 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 8 Aug 2011 12:51:00 -0600 Subject: [PATCH 02/16] ... --- Changelog.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.yaml b/Changelog.yaml index 887ac4e05d..bf3f7c907c 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -251,8 +251,8 @@ - title: Techcrunch and Pecat author: Darko Miletic - - title: Vio Mundo, IDG Now and Tojolaco - author: Diniz Bortoletto + - title: "Vio Mundo, IDG Now! and Tojolaco" + author: Diniz Bortolotto - title: Geek and Poke, Automatiseringgids IT author: DrMerry From b06e4419bce6af815ec2ff598f2aed1b11ba89c7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 8 Aug 2011 12:55:31 -0600 Subject: [PATCH 03/16] Blog Escrevinhador by Diniz Bortolotto --- recipes/escrevinhador.recipe | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 recipes/escrevinhador.recipe diff --git a/recipes/escrevinhador.recipe b/recipes/escrevinhador.recipe new file mode 100644 index 0000000000..0003b798c6 --- /dev/null +++ b/recipes/escrevinhador.recipe @@ -0,0 +1,28 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class Escrevinhador(BasicNewsRecipe): + title = 'Blog Escrevinhador' + __author__ = 'Diniz Bortolotto' + description = 'Posts do Blog Escrevinhador' + publisher = 'Rodrigo Viana' + oldest_article = 5 + max_articles_per_feed = 20 + category = 'news, politics, Brazil' + language = 'pt_BR' + publication_type = 'news and politics portal' + use_embedded_content = False + no_stylesheets = True + remove_javascript = True + + feeds = [(u'Blog Escrevinhador', u'http://www.rodrigovianna.com.br/feed')] + + reverse_article_order = True + + remove_tags_after = [dict(name='div', attrs={'class':'text'})] + + remove_tags = [ + dict(id='header'), + dict(name='p', attrs={'class':'tags'}), + dict(name='div', attrs={'class':'sociable'}) + ] + From 8d14a2f98d269ede9204774b32a09b2f041f5f74 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 9 Aug 2011 11:24:37 -0600 Subject: [PATCH 04/16] Start work on preferences widget to set keyboard shortcuts --- imgsrc/keyboard-prefs.svg | 912 +++++++++++++++++++++ resources/images/keyboard-prefs.png | Bin 0 -> 5571 bytes src/calibre/customize/builtins.py | 15 +- src/calibre/gui2/actions/__init__.py | 34 +- src/calibre/gui2/actions/choose_library.py | 5 +- src/calibre/gui2/actions/device.py | 6 +- src/calibre/gui2/actions/restart.py | 2 +- src/calibre/gui2/keyboard.py | 174 +++- src/calibre/gui2/library/models.py | 2 +- src/calibre/gui2/preferences/keyboard.py | 44 + 10 files changed, 1173 insertions(+), 21 deletions(-) create mode 100644 imgsrc/keyboard-prefs.svg create mode 100644 resources/images/keyboard-prefs.png create mode 100644 src/calibre/gui2/preferences/keyboard.py diff --git a/imgsrc/keyboard-prefs.svg b/imgsrc/keyboard-prefs.svg new file mode 100644 index 0000000000..bcdc07f7b8 --- /dev/null +++ b/imgsrc/keyboard-prefs.svg @@ -0,0 +1,912 @@ + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/images/keyboard-prefs.png b/resources/images/keyboard-prefs.png new file mode 100644 index 0000000000000000000000000000000000000000..68b8d7fb88bffc1a9eaaf9cd8df34c41a766920a GIT binary patch literal 5571 zcmbVQWmuF=xPEs*xL20BV1%xGqC6*3}rC})%7eQE5*pHT!*d;$g2|*e}Y5@U} zlx|RJDM3OI&--21`FsAHH~-Ac^*l3k$1^d;a2;AI4k`cuX!Ueqrr;m*-%CLTe!Eqj z2EiYh^FtjN@b|wvzpXSC09es_um@&n+^)T?kJ-2OE4Se%^x_5*bu3AC`Y6Wxz0{Or z6lIx3vRyBw{;E+xnEi|dIG7#6Bvsj8s%*ZL(kJ+TgeAfBDEL+)Qb?GX^ypI9_r&Y! zi|wd2OUHw&E>wu;yH#y1CnzNu?xdZE!6(Fezop-m;4`>*!KtqCe_X47#l!A-7CvYC zMwwvSN@n|6-zmr8s4tx}yT>mVyDr=Om3p#@0Rx{U@1W?XA4>l{J8LZ>s58t*pUrAD?T8gg;Mzq+uV8tO44Pc$VuL*Xf2JiWsW4 zWlo4JkV(Qz)uwmAmRR}f=}}g#OvC!WQ&%(?Dd1_o4$4tldL4HcM#m7j2hal9kckIL z6t_0BNJMg^J|Q$u-IdEyQor7z<)v(+iR}O32yJ;>9af5Yg5lVdYv)lXet+YzXV>Vv zFkmdi@Vi{tBeLyoxiAsmNYV1Z-dr zG7N#aaN%n9lk-1UZ{0I)ya>%!xCV_JNEYshL8MQ|?5EAXsQ8@ZWGJ{1s2KG0DVyFX z=U(#$4<0j2u4VFiI8H|@y#40Xdxt)}@>7xC!HuKN{Zsxo%ulOGBGu*mf68)wSEfP; z$b_lh)F?3S(d5kMl*Pl1^ekDf#TN21#Za8SVYZ-Cr?b_TB$(sotjX#K2zb7mMiir!dRu$#lk)3*|-^B+?4Iig6@3hlS0{G;ejh!yX$EKlq^~gB-v#(I9&C|We4MH=ztCdwKs$5uhZi5S0r-N}dTHldo={^{nYAve?3!OBCo>{iC@S8}h1A>kqQL=HF3*p8 zgF{1GOM@*5F-sd05{v=*0;%Xfzor8A<`vhPV0@8J7emPNo}b*v5Vy6kfcrY$fRuGV zxNkEs5k<`wkF?UvQ;S&S?NidOp_Wvn)Jk;hp~Q5Ga?v3>UtH_`v^DRLrp-0)|LpId z)Bi>!I7@{ckLpafg~~hEu>U+)IoV%wxCg%zfKlgl6eA|Q&CkisHnz3({&&3gMMlQ; zvUl4`G8W#3<5+}GZ-qil;>_%<*LE@+a@o{hDdgvEx|^yr0D8aev^wlOP|W%RsrO_B z1i-0;eDJ}2?2rzwzTwjUx?rn-HqVzWd{;@47{0yx`%gFmUAsz90+ueP7lvsCPZT6@ zCwmLj0Q#Vl{P3Wgo^vZ9ApyXkRUXyhaS9=k-sFJeyDgtga>suqtUnOyN6+P2llF$5 z)w7lcDJ6XRqzb6p+U5w7`>zt{+sYbd0%H5t&VEffKma4v^MCu{#C7AE;8n%L;Ga+( za>vj{et!O@!0%K*Z2=aG4LJH?2uyOTH`eF<8N$jnEZhMXrl7HL3e7ROxadnnPQg!u z2K7u>ZV67p`;u^%# ze89upVFpP>PLJ=vL@#rh!|Lfp4f@a-kx;Y~5@`gZ6^nD@o2ycN{1=sSc^`73s=f> zYnq1vvFa@8uxtDE5*>ko%n&PhcXu~{IX~Lq-0;qhj*NsLt6a9mie1;%uVv8jiez40 zg#(#PZv7Ce_YFU7lBa6>YCSIx`S{lZ741Hv88J=0*7$w1@d}^iXy!Jid+uMkQt^r0 z%4F&h#6KM*^l1sHY)yf{@8=*cfR2wLNAY##mhYWCJSc$wwomHHZdaRqv=AO;S*buv zOM7E@ac*`teyxJbu?2UwiDb(??=RrjNdy3%P@>eA-1~FO)?V;Oj*5(F!yC!N8-{Ij zFg}QS9;!%|V{c+&f*mA?I***cL+<|!i5*t2!d8|xj;!e*qC=j0^Uc8VzynV~I8O4n zG3Py>%DA_nJ>=Dtl*gCe5^!E9Q zhCTs2-BQ{!xNk~myD55RyKMm&9!kjaa_7s5totN%E4f;5tjjCwhcZuIP?LC zi3ZB$n=-!B)sVcfpOkm)TV7c@JpZQaheGxI7|MxqVq?JSoTwHCy(kpwWzVCHA>EER z;8s^!6crRytxJkWxt9L9IOR{)U9O*cBr^ui&p|JzUm8A@%}PmKH7{?BOzm|3F{qLX z{>wmgbo9u`2-@&?4iE4vEyodS--osB%Pf`7zc zmv|JvJJ*QZ_=*Qp&_*KpbJ44mKJ!hCqaG8r_>X}Gzp8okYJZMXiyu535`Hsyi-97)s)}x^ z%3kK{pj)i~95@)!q+b~~Qmd~w$x;Z}rWKi|ON6N4c%>+iQ_a>}F(A$h3T|~< z&G<~3&3S|hDEvA-DfU~Q&#~c%+5oec&LJ}%NRqoXDU1_taGp4vMnyK|ZHemo$yX_4em z2=cZxGj8)yjn$W?h&u`iiHUq!1})!V4$sD?7Oh)ulLksbGR;e*M_2_uh>ME@$CjBD zpQyjM)oN=)+7?Q5Qp3oE&D?6O5iP?T%#R|%!ni;VYi^#&#F(114h;>B$X4FQ1vYa9 zHsieEE=g8mZbVCSRzpL>J8SFT;83{JCI`J-rr0Ho*hDup(=3YvTO}t$#%t%`@E&qd zY$^;ZGFeGz!>D>36c)cW5HLX?UV6x8LjZI0+GO3^l1fT8OmJE3UK9eH*DM+L<)ia4 zf}Z)elmL-lIH7<4G)Yt9jQtpDnXeNmWmSf~Mn%ayVqUVBpD!n)pnz^JDq36e^7azJ9-W^_&WfObXY2&DGEj|_1F0s>=dS7&Q~ z)!&@=Yx+@5bOn-M-*!?ph>l|qO0U-5%Zrv*EoM+>eICL`A3M!e<3NY?*i1MUL@T;IeBE|Dy?1 zJ9S6jkPoU41U+UltEj~#Gnkhwy*i4Lma@LIhUsdSCoPJC`YviYd+chgOJet!FDdU1iB38t2E@32EGf^b*E zG9I^$?1pWp<9s2GgbXdpZaRzJD(zp@S?ewZAAYbyh;Yep#6JaC-gJV4-u;SL1xoC$ zmOOl->g_w5WQvZ4qHkprzbsb?&a-q36r?oQY62gau&g~->%bd4tQUG>&M$afOBo0a z7-Oj0CN(6FR0ooE3F|Yy|IUh3{%=P{V5A!^%b}%&zia(N_r3v3?>m$G#P@_4Ej>P< za|ijwbTMb_T;A8+=6(f-VvUdID#nbt$wEg2#~!}9i_b{JQ^4yJnzTHTgqY zpYD?ZAJ2c}Sk-wXBSU>G$BFT~1ij-dbdCRDKVf*saI>(&ri|it!sO^Eq~rPA4>AjB z@!)Nz8Y>zQd!OBE&z4`(zaIR4Fo7^CC@&v;g06p9n^Ie|#u5Xo_FvH$R~1xvuI1CG zM>ip1dJ(wsX&Zzd9^35*Z;LycZHHNUy+g`RCKU6@B@P0 z+t06Wd71aq*(x zzXiq=ao5GApX&xAl9PesM{q zhg)AvrIo8Ew1Nw>`#goDuAyNzTA{qF6jlDUD7_}+S2gJC_?hfKh1~#6S0Ctfu&B9) z8IHNPc-B9`YrJaCUcNrB3VFw)M+f+gdk$LbD%K(W9&lMmf_{pqBI}M%PdWF=jY)Z3 z=}pJ;qZT&mGIiOcdpWZ3)TL{08|3cYTitD3BFo>Qj890&qWQYiw|!MOt3T(fcv!?F ze=5N$$f%+WEMSJ&m##!(olTjUS(^|manicItlZt&v0( z*VIS>9c`zJaWl22uAf@Ai)T@6~PI!_*2X~|gl%%Kua2V&j}@u7nO5tUIy zmEB!;kCjTRnl6}~*;&|Q$8-}_X1+rq(O;77OG%TH79QDd6xO+_&u!55tv2qiF8ZhE zgl#9EoG&8Thbb+-UJcBGi{UC@f={8s2p{y;?yi<}7NI~BE2*GBp+41B`_qwckp2%v z@DWMJ1cf?odbW3BU%aA>fUB?&v3lAI|9FoAg2vl4C2oOaG z;&MhRt5NIUM*?8Ps+S}kpyfQc*l*|Tt9aDLak>=I?wZM#>^gql#imFSB99+*FuLt+ zq>*xn=F-&E^zih|a`qSGk87&k3dRXRY3S*ZM?Z$NpMe!cfgoXNkXEo&PsYO4@Kqrn zphl~rqCx|v-MZI84U$UNWTkDC)0Y9x1r{Yg2CRDup55_EM6YM?=Esmjgkg9I>sUqV6UL^qCQ2$%ht=`mA-crac);i3|f>V*e=73g0(Kzld%Q(7p=Oe6~Q z=XR~ZLuJ+$`u5;?LS8^|m9qjX;?_rhk&bl=3r2P1q<{{umI%Pk$*E~%MF0EuZ-%&@ z|2!fHRN;c`Usl^{O)=1|AP#VDJpIPxTNWzk*x0cZ=iD(tykKH#D zw57Z!#WYzT!gA%+Mbb4y(z`Y{g_vSqZE-)#9^%vS@bxWee?O{UIni@nH+kFX&V~z% z{vobRjGG?_iPgO?#vIoJR;O{`+7BA##yG0*kV~G&%DcYKs~L2W?xHu?HLGzO&NaNK zEjFV+Iu8RGcHEqPFas10(pWd^%=Y6+V246IYPcL5#lgW52wWnONUd_`!-B6nJL|Gj z`9k_s9cWpOAsAn>qi|Y_Eb6C}mz2J}n4r1&!!F9q+(K(fb^{FwofNE;(zW2{K=QN9 zlk<(do9LA&wkv)vI;^`Xt7y7@F<8!CNC1tWK>Cb8&3tf0vHE9EgK`mJ$y^Hhf$-za zQHf6Bwvq7i+~}JvcNxlgCINdzu~@xMp;qrSCZCNczd_yW>8xsJt&ayD_%-z9TP`|T zmAz8b!UP!5v5o^wBlT|3GP@sVj4`P-cLed&=}SUE0cFWuCoBcJjGNF`T*n7e(Ap8> zJH@M3$XZPf=>vn$Q|6+A4fOJndf(*7LZ$nots?(P)#jyS7*4auC#y}iMvmJAG9|5A zwF!>TCvrNQO<&ILo)<&aWcoGAoJ}ESGJ^M{YrL61GUUW)yvgJ#`EseJ`~SKw>klJD YST8= len(self.column_to_dc_map): return NONE - if role in (Qt.DisplayRole, Qt.EditRole): + if role in (Qt.DisplayRole, Qt.EditRole, Qt.ToolTipRole): return self.column_to_dc_map[col](index.row()) elif role == Qt.BackgroundRole: if self.id(index) in self.ids_to_highlight_set: diff --git a/src/calibre/gui2/preferences/keyboard.py b/src/calibre/gui2/preferences/keyboard.py new file mode 100644 index 0000000000..ccc3a390d3 --- /dev/null +++ b/src/calibre/gui2/preferences/keyboard.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from PyQt4.Qt import QVBoxLayout + +from calibre.gui2.preferences import (ConfigWidgetBase, test_widget) +from calibre.gui2.keyboard import ShortcutConfig + +class ConfigWidget(ConfigWidgetBase): + + def genesis(self, gui): + self.gui = gui + self.conf_widget = ShortcutConfig(self) + self.conf_widget.changed_signal.connect(self.changed_signal) + self._layout = l = QVBoxLayout() + self.setLayout(l) + l.addWidget(self.conf_widget) + + def initialize(self): + ConfigWidgetBase.initialize(self) + self.conf_widget.initialize(self.gui.keyboard) + + def restore_defaults(self): + ConfigWidgetBase.restore_defaults(self) + self.conf_widget.restore_defaults() + + def commit(self): + self.conf_widget.commit() + return ConfigWidgetBase.commit(self) + + def refresh_gui(self, gui): + gui.keyboard.finalize() + +if __name__ == '__main__': + from PyQt4.Qt import QApplication + app = QApplication([]) + test_widget('Advanced', 'Keyboard') + From 6affbface3b6765aa277d0c84ac6bc05488c1d91 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 9 Aug 2011 11:28:44 -0600 Subject: [PATCH 05/16] ... --- src/calibre/gui2/actions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index aedb10c4b3..5f1c55c909 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -113,7 +113,7 @@ class InterfaceAction(QObject): @property def unique_name(self): bn = self.__class__.__name__ - if hasattr(self.interface_action_base_plugin, 'name'): + if getattr(self.interface_action_base_plugin, 'name'): bn = self.interface_action_base_plugin.name return u'%s (%s)'%(bn, self.name) From 6e557a77ee0ce2e32c6da9b1eb1a5ac790c20f6c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 9 Aug 2011 11:31:21 -0600 Subject: [PATCH 06/16] ... --- src/calibre/gui2/actions/__init__.py | 2 +- src/calibre/gui2/keyboard.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 5f1c55c909..37221ada3f 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -115,7 +115,7 @@ class InterfaceAction(QObject): bn = self.__class__.__name__ if getattr(self.interface_action_base_plugin, 'name'): bn = self.interface_action_base_plugin.name - return u'%s (%s)'%(bn, self.name) + return u'Interface Action: %s (%s)'%(bn, self.name) def create_action(self, spec=None, attr='qaction'): if spec is None: diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index e3563867e3..67a39b44e3 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -172,10 +172,10 @@ class Delegate(QStyledItemDelegate): # {{{ keys = _('None') else: keys = ', '.join(keys) - html = '

%s

%s: %s'%(shortcut['name'], _('Shortcuts'), keys) + html = '%s
%s: %s'%(shortcut['name'], _('Shortcuts'), keys) else: # Group - html = '

%s

'%data.data + html = '

%s

'%data.data doc = QTextDocument() doc.setHtml(html) return doc From 6fe08ffeb7229cef01bbb112221e4e73d7b67bad Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 07:52:59 -0600 Subject: [PATCH 07/16] ... --- resources/content_server/browse/browse.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/content_server/browse/browse.html b/resources/content_server/browse/browse.html index cf17742c87..746c4d6c6c 100644 --- a/resources/content_server/browse/browse.html +++ b/resources/content_server/browse/browse.html @@ -11,7 +11,7 @@ - + From 622ed308e7cea27b854082e529d581456766b7b1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 08:18:27 -0600 Subject: [PATCH 08/16] ... --- src/calibre/gui2/dialogs/scheduler.py | 1 + src/calibre/gui2/preferences/adding.ui | 2 +- src/calibre/translations/calibre.pot | 273 ++++++++++++++----------- 3 files changed, 158 insertions(+), 118 deletions(-) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index e45148c405..6d152dc14b 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -193,6 +193,7 @@ class SchedulerDialog(QDialog, Ui_Dialog): self.recipe_model = recipe_model self.recipe_model.do_refresh() self.count_label.setText( + # NOTE: Number of news sources _('%s news sources') % self.recipe_model.showing_count) diff --git a/src/calibre/gui2/preferences/adding.ui b/src/calibre/gui2/preferences/adding.ui index f9a2c74444..e1d00f975d 100644 --- a/src/calibre/gui2/preferences/adding.ui +++ b/src/calibre/gui2/preferences/adding.ui @@ -27,7 +27,7 @@ - Read &metadata from &file contents rather than file name + Read &metadata from file contents rather than file name diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index a42f0833e7..19eecb0045 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.8.13\n" -"POT-Creation-Date: 2011-08-08 12:45+MDT\n" -"PO-Revision-Date: 2011-08-08 12:45+MDT\n" +"POT-Creation-Date: 2011-08-10 08:16+MDT\n" +"PO-Revision-Date: 2011-08-10 08:16+MDT\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -150,7 +150,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:128 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:47 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:766 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:371 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:372 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:185 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:200 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:404 @@ -200,6 +200,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/__init__.py:148 #: /home/kovid/work/calibre/src/calibre/ebooks/html/to_zip.py:81 +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:228 msgid "Customize" msgstr "" @@ -545,6 +546,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1077 #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1089 #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1100 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1111 msgid "Advanced" msgstr "" @@ -600,10 +602,19 @@ msgid "Fine tune how calibre behaves in various contexts" msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1098 -msgid "Miscellaneous" +msgid "Keyboard" msgstr "" #: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1104 +msgid "Customize the keyboard shortcuts used by calibre" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1109 +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:80 +msgid "Miscellaneous" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1115 msgid "Miscellaneous advanced configuration" msgstr "" @@ -820,7 +831,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/db/backend.py:270 #: /home/kovid/work/calibre/src/calibre/db/backend.py:279 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:230 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:231 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:71 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:667 #: /home/kovid/work/calibre/src/calibre/library/database2.py:130 @@ -968,7 +979,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:1079 #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:1114 #: /home/kovid/work/calibre/src/calibre/gui2/actions/fetch_news.py:73 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:452 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:453 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1139 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:1141 #: /home/kovid/work/calibre/src/calibre/library/database2.py:330 @@ -3507,7 +3518,7 @@ msgstr "" msgid "tag browser categories not to display" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:492 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:494 msgid "Choose Files" msgstr "" @@ -3788,11 +3799,7 @@ msgid "Select destination for %(title)s.%(fmt)s" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:82 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar.py:57 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:171 -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:125 -#, python-format -msgid "%d books" +msgid "Choose Library" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:83 @@ -3803,122 +3810,130 @@ msgstr "" msgid "Switch/create library..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:103 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:89 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar.py:57 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:171 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:125 +#, python-format +msgid "%d books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:104 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:87 msgid "Quick switch" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:105 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:106 #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:88 msgid "Rename library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:107 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:108 msgid "Remove library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:110 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:111 #: /home/kovid/work/calibre/src/calibre/gui2/actions/random.py:17 msgid "Pick a random book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:130 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:131 msgid "Library Maintenance" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:132 msgid "Library metadata backup status" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:136 msgid "Start backing up metadata of all books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:140 msgid "Check library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:143 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:144 msgid "Restore database" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:215 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:216 msgid "Rename" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:216 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:217 #, python-format msgid "Choose a new name for the library %s. " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:218 msgid "Note that the actual library folder will be renamed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:224 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:225 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:726 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:201 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:291 msgid "Already exists" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:225 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:226 #, python-format msgid "The folder %s already exists. Delete it first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:229 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:283 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:230 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:284 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:70 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:666 msgid "Too long" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:237 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:238 msgid "Rename failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:238 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:239 #, python-format msgid "Failed to rename the library at %s. The most common cause for this is if one of the files in the library is open in another program." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:252 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:253 msgid "Library removed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:253 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:254 #, python-format msgid "The library %s has been removed from calibre. The files remain on your computer, if you want to delete them, you will have to do so manually." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:266 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:267 msgid "none" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:267 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:268 msgid "Backup status" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:268 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:269 #, python-format msgid "Book metadata files remaining to be written: %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:274 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:275 msgid "Backup metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:275 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:276 msgid "Metadata will be backed up while calibre is running, at the rate of approximately 1 book every three seconds." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:284 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:285 #, python-format msgid "Path to library too long. Must be less than %d characters. Move your library to a location with a shorter path using Windows Explorer, then point calibre to the new location and try again." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:319 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:320 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/plugin_updater.py:733 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:106 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/restore_library.py:111 @@ -3927,11 +3942,11 @@ msgstr "" msgid "Success" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:320 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:321 msgid "Found no errors in your calibre library database. Do you want calibre to check if the files in your library match the information in the database?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:325 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:326 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:160 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:741 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:956 @@ -3941,40 +3956,40 @@ msgstr "" msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:326 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:327 msgid "Database integrity check failed, click Show details for details." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:331 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:332 msgid "No problems found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:333 msgid "The files in your library match the information in the database." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:341 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:342 msgid "No library found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:342 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:343 #, python-format msgid "No existing calibre library was found at %s. It will be removed from the list of known libraries." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:408 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:413 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:409 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:414 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:178 #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:100 #: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:886 msgid "Not allowed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:409 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:410 msgid "You cannot change libraries while using the environment variable CALIBRE_OVERRIDE_DATABASE_PATH." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:414 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:415 msgid "You cannot change libraries while jobs are running." msgstr "" @@ -4194,49 +4209,53 @@ msgid "Connect to Bambook" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:56 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:73 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:77 msgid "Start Content Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:75 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:73 +msgid "Start/stop content server" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:79 msgid "Stop Content Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:86 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:105 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:109 msgid "Email to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:94 msgid "Email to and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:99 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:103 msgid "(delete from library)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:114 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:118 msgid "Setup email based sharing of books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:136 msgid "D" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:136 msgid "Send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:154 msgid "Connect/share" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:187 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:191 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:79 msgid "Stopping" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:188 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:192 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/server.py:80 msgid "Stopping server, this could take upto a minute, please wait..." msgstr "" @@ -4488,12 +4507,12 @@ msgid "Cannot configure before calibre is restarted." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/restart.py:14 -msgid "&Restart" +#: /home/kovid/work/calibre/src/calibre/utils/pyconsole/main.py:59 +msgid "Ctrl+R" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/restart.py:14 -#: /home/kovid/work/calibre/src/calibre/utils/pyconsole/main.py:59 -msgid "Ctrl+R" +msgid "Restart" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:24 @@ -8589,70 +8608,71 @@ msgstr "" msgid "Note: You can set intervals of less than a day, by typing the value manually." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:196 +#. NOTE: Number of news sources +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:197 #, python-format msgid "%s news sources" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:310 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:311 msgid "Need username and password" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:311 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:312 msgid "You must provide a username and/or password to use this news source." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:351 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:352 msgid "Account" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:352 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:353 msgid "(optional)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:353 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:354 msgid "(required)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:370 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:371 msgid "Created by: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:377 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:378 msgid "Last downloaded: never" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:378 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:379 msgid "never" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:384 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:385 #, python-format msgid "%(days)d days, %(hours)d hours and %(mins)d minutes ago" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:400 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:401 msgid "Last downloaded:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:428 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:429 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:206 msgid "Schedule news download" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:431 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:432 msgid "Add a custom news source" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:436 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:437 msgid "Download all scheduled new sources" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:541 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:542 msgid "No internet connection" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:542 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:543 msgid "Cannot download news as no internet connection is active" msgstr "" @@ -9656,6 +9676,60 @@ msgstr[1] "" msgid "Do you really want to stop all non-device jobs?" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:200 +#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/model.py:86 +#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/model.py:204 +msgid "Custom" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:207 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:81 +msgid "&Alternate shortcut:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:207 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:76 +msgid "&Shortcut:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:212 +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:261 +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:296 +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:320 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:48 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:78 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:83 +#: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/chooser_widget_ui.py:83 +#: /home/kovid/work/calibre/src/calibre/gui2/store/search/search_ui.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/store/search_ui.py:113 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:358 +msgid "None" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:235 +#, python-format +msgid "Default (some keys may conflict): %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:255 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:59 +msgid "Press a key..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:276 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:80 +msgid "Already assigned" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:278 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:82 +msgid "already assigned to" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:323 +msgid "Shortcuts" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:57 msgid "Eject this device" msgstr "" @@ -10517,7 +10591,7 @@ msgid "Here you can control how calibre will read metadata from the files you ad msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:66 -msgid "Read &metadata from &file contents rather than file name" +msgid "Read &metadata from file contents rather than file name" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:67 @@ -12507,28 +12581,6 @@ msgstr "" msgid "({0} of all)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:48 -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:78 -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:83 -#: /home/kovid/work/calibre/src/calibre/gui2/store/config/chooser/chooser_widget_ui.py:83 -#: /home/kovid/work/calibre/src/calibre/gui2/store/search/search_ui.py:138 -#: /home/kovid/work/calibre/src/calibre/gui2/store/search_ui.py:113 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:358 -msgid "None" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:59 -msgid "Press a key..." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:80 -msgid "Already assigned" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:82 -msgid "already assigned to" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:132 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:223 msgid " or " @@ -12559,19 +12611,11 @@ msgstr "" msgid "&Custom" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:76 -msgid "&Shortcut:" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:77 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:82 msgid "Click to change" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:81 -msgid "&Alternate shortcut:" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/store/basic_config_widget_ui.py:38 msgid "Added Tags:" msgstr "" @@ -16190,11 +16234,6 @@ msgstr "" msgid "Scheduled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/model.py:86 -#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/model.py:204 -msgid "Custom" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:118 msgid "Next section" msgstr "" From 07a90423125273bfd0e29aeba3d9c7fc81d14693 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 11:27:18 -0600 Subject: [PATCH 09/16] Allow customization of the keyboard shortcuts used in calibre via Preferences->Advanced->Keyboard --- src/calibre/gui2/keyboard.py | 340 ++++++++++++++++++++++++++++++----- 1 file changed, 299 insertions(+), 41 deletions(-) diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index 67a39b44e3..f2a9f8d886 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -8,29 +8,70 @@ __copyright__ = '2011, Kovid Goyal ' __docformat__ = 'restructuredtext en' from collections import OrderedDict +from functools import partial from PyQt4.Qt import (QObject, QKeySequence, QAbstractItemModel, QModelIndex, - Qt, QStyledItemDelegate, QTextDocument, QStyle, pyqtSignal, - QApplication, QSize, QRectF, QWidget, QHBoxLayout, QTreeView) + Qt, QStyledItemDelegate, QTextDocument, QStyle, pyqtSignal, QFrame, + QApplication, QSize, QRectF, QWidget, QTreeView, + QGridLayout, QLabel, QRadioButton, QPushButton, QToolButton, QIcon) from calibre.utils.config import JSONConfig from calibre.constants import DEBUG from calibre import prints from calibre.utils.icu import sort_key -from calibre.gui2 import NONE +from calibre.gui2 import NONE, error_dialog ROOT = QModelIndex() class NameConflict(ValueError): pass +def finalize(shortcuts, custom_keys_map={}): # {{{ + ''' + Resolve conflicts and assign keys to every action in shorcuts, which must + be a OrderedDict. User specified mappings of unique names to keys (as a + list of strings) should be passed in in custom_keys_map. Return a mapping + of unique names to resolved keys. Also sets the set_to_defaul member + correctly for each shortcut. + ''' + seen, keys_map = {}, {} + for unique_name, shortcut in shortcuts.iteritems(): + custom_keys = custom_keys_map.get(unique_name, None) + if custom_keys is None: + candidates = shortcut['default_keys'] + shortcut['set_to_default'] = True + else: + candidates = custom_keys + shortcut['set_to_default'] = False + keys = [] + for x in candidates: + ks = QKeySequence(x, QKeySequence.PortableText) + x = unicode(ks.toString(QKeySequence.PortableText)) + if x in seen: + if DEBUG: + prints('Key %r for shortcut %s is already used by' + ' %s, ignoring'%(x, shortcut['name'], seen[x]['name'])) + continue + seen[x] = shortcut + keys.append(ks) + keys = tuple(keys) + #print (111111, unique_name, candidates, keys) + + keys_map[unique_name] = keys + ac = shortcut['action'] + if ac is not None: + ac.setShortcuts(list(keys)) + + return keys_map + +# }}} + class Manager(QObject): # {{{ def __init__(self, parent=None): QObject.__init__(self, parent) self.config = JSONConfig('shortcuts/main') - self.custom_keys_map = {} self.shortcuts = OrderedDict() self.keys_map = {} self.groups = {} @@ -48,36 +89,10 @@ class Manager(QObject): # {{{ self.groups[group] = self.groups.get(group, []) + [unique_name] def finalize(self): - self.custom_keys_map = {un:tuple(keys) for un, keys in self.config.get( - 'map', {}).iteritems()} + custom_keys_map = {un:tuple(keys) for un, keys in self.config.get( + 'map', {}).iteritems()} + self.keys_map = finalize(self.shortcuts, custom_keys_map=custom_keys_map) - seen = {} - for unique_name, shortcut in self.shortcuts.iteritems(): - custom_keys = self.custom_keys_map.get(unique_name, None) - if custom_keys is None: - candidates = shortcut['default_keys'] - else: - candidates = custom_keys - keys = [] - for x in candidates: - ks = QKeySequence(x, QKeySequence.PortableText) - x = unicode(ks.toString(QKeySequence.PortableText)) - if x in seen: - if DEBUG: - prints('Key %r for shortcut %s is already used by' - ' %s, ignoring'%(x, shortcut['name'], seen[x]['name'])) - continue - seen[x] = shortcut - keys.append(ks) - keys = tuple(keys) - #print (111111, unique_name, candidates, keys) - - self.keys_map[unique_name] = keys - ac = shortcut['action'] - if ac is not None: - ac.setShortcuts(list(keys)) - - self.groups = {g:frozenset(v) for g, v in self.groups.iteritems()} # }}} # Model {{{ @@ -98,6 +113,10 @@ class Node(object): def __getitem__(self, row): return self.children[row] + def __iter__(self): + for child in self.children: + yield child + class ConfigModel(QAbstractItemModel): def __init__(self, keyboard, parent=None): @@ -105,7 +124,7 @@ class ConfigModel(QAbstractItemModel): self.keyboard = keyboard groups = sorted(keyboard.groups, key=sort_key) - shortcut_map = {k:dict(v) for k, v in + shortcut_map = {k:v.copy() for k, v in self.keyboard.shortcuts.iteritems()} for un, s in shortcut_map.iteritems(): s['keys'] = tuple(self.keyboard.keys_map[un]) @@ -119,6 +138,12 @@ class ConfigModel(QAbstractItemModel): self.data = [Node(group_map, shortcut_map, group) for group in groups] + @property + def all_shortcuts(self): + for group in self.data: + for sc in group: + yield sc + def rowCount(self, parent=ROOT): ip = parent.internalPointer() if ip is None: @@ -154,13 +179,186 @@ class ConfigModel(QAbstractItemModel): return ip return NONE + def flags(self, index): + ans = QAbstractItemModel.flags(self, index) + ip = index.internalPointer() + if getattr(ip, 'is_shortcut', False): + ans |= Qt.ItemIsEditable + return ans + + def restore_defaults(self): + shortcut_map = {} + for node in self.all_shortcuts: + sc = node.data + shortcut_map[sc['unique_name']] = sc + shortcuts = OrderedDict([(un, shortcut_map[un]) for un in + self.keyboard.shortcuts]) + keys_map = finalize(shortcuts) + for node in self.all_shortcuts: + s = node.data + s['keys'] = tuple(keys_map[s['unique_name']]) + for r in xrange(self.rowCount()): + group = self.index(r, 0) + num = self.rowCount(group) + if num > 0: + self.dataChanged.emit(self.index(0, 0, group), + self.index(num-1, 0, group)) + + def commit(self): + kmap = {} + for node in self.all_shortcuts: + sc = node.data + if sc['set_to_default']: continue + keys = [unicode(k.toString(k.PortableText)) for k in sc['keys']] + kmap[sc['unique_name']] = keys + self.keyboard.config['map'] = kmap + + +# }}} + +class Editor(QFrame): # {{{ + + editing_done = pyqtSignal(object) + + def __init__(self, parent=None): + QFrame.__init__(self, parent) + self.setFocusPolicy(Qt.StrongFocus) + self.setAutoFillBackground(True) + self.capture = 0 + + self.setFrameShape(self.StyledPanel) + self.setFrameShadow(self.Raised) + self._layout = l = QGridLayout(self) + self.setLayout(l) + + self.header = QLabel('') + l.addWidget(self.header, 0, 0, 1, 2) + + self.use_default = QRadioButton('') + self.use_custom = QRadioButton(_('Custom')) + l.addWidget(self.use_default, 1, 0, 1, 3) + l.addWidget(self.use_custom, 2, 0, 1, 3) + self.use_custom.toggled.connect(self.custom_toggled) + + off = 2 + for which in (1, 2): + text = _('&Shortcut:') if which == 1 else _('&Alternate shortcut:') + la = QLabel(text) + la.setStyleSheet('QLabel { margin-left: 1.5em }') + l.addWidget(la, off+which, 0, 1, 3) + setattr(self, 'label%d'%which, la) + button = QPushButton(_('None'), self) + button.clicked.connect(partial(self.capture_clicked, which=which)) + button.keyPressEvent = partial(self.key_press_event, which=which) + setattr(self, 'button%d'%which, button) + clear = QToolButton(self) + clear.setIcon(QIcon(I('clear_left.png'))) + clear.clicked.connect(partial(self.clear_clicked, which=which)) + setattr(self, 'clear%d'%which, clear) + l.addWidget(button, off+which, 1, 1, 1) + l.addWidget(clear, off+which, 2, 1, 1) + la.setBuddy(button) + + self.done_button = doneb = QPushButton(_('Done'), self) + l.addWidget(doneb, 0, 2, 1, 1) + doneb.clicked.connect(lambda : self.editing_done.emit(self)) + l.setColumnStretch(0, 100) + + self.custom_toggled(False) + + def initialize(self, shortcut, all_shortcuts): + self.header.setText('%s: %s'%(_('Customize'), shortcut['name'])) + self.all_shortcuts = all_shortcuts + self.shortcut = shortcut + + self.default_keys = [QKeySequence(k, QKeySequence.PortableText) for k + in shortcut['default_keys']] + self.current_keys = list(shortcut['keys']) + default = ', '.join([unicode(k.toString(k.NativeText)) for k in + self.default_keys]) + if not default: default = _('None') + current = ', '.join([unicode(k.toString(k.NativeText)) for k in + self.current_keys]) + if not current: current = _('None') + + self.use_default.setText(_('Default: %s [Currently not conflicting: %s]')% + (default, current)) + + if shortcut['set_to_default']: + self.use_default.setChecked(True) + else: + self.use_custom.setChecked(True) + for key, which in zip(self.current_keys, [1,2]): + button = getattr(self, 'button%d'%which) + button.setText(key.toString(key.NativeText)) + + def custom_toggled(self, checked): + for w in ('1', '2'): + for o in ('label', 'button', 'clear'): + getattr(self, o+w).setEnabled(checked) + + def capture_clicked(self, which=1): + self.capture = which + button = getattr(self, 'button%d'%which) + button.setText(_('Press a key...')) + button.setFocus(Qt.OtherFocusReason) + button.setStyleSheet('QPushButton { font-weight: bold}') + + def clear_clicked(self, which=0): + button = getattr(self, 'button%d'%which) + button.setText(_('None')) + + def key_press_event(self, ev, which=0): + code = ev.key() + if self.capture == 0 or code in (0, Qt.Key_unknown, + Qt.Key_Shift, Qt.Key_Control, Qt.Key_Alt, Qt.Key_Meta, + Qt.Key_AltGr, Qt.Key_CapsLock, Qt.Key_NumLock, Qt.Key_ScrollLock): + return QWidget.keyPressEvent(self, ev) + button = getattr(self, 'button%d'%which) + button.setStyleSheet('QPushButton { font-weight: normal}') + sequence = QKeySequence(code|(int(ev.modifiers())&~Qt.KeypadModifier)) + button.setText(sequence.toString(QKeySequence.NativeText)) + self.capture = 0 + dup_desc = self.dup_check(sequence) + if dup_desc is not None: + error_dialog(self, _('Already assigned'), + unicode(sequence.toString(QKeySequence.NativeText)) + ' ' + + _('already assigned to') + ' ' + dup_desc, show=True) + self.clear_clicked(which=which) + + def dup_check(self, sequence): + for sc in self.all_shortcuts: + if sc is self.shortcut: continue + for k in sc['keys']: + if k == sequence: + return sc['name'] + + @property + def custom_keys(self): + if self.use_default.isChecked(): + return None + ans = [] + for which in (1, 2): + button = getattr(self, 'button%d'%which) + t = unicode(button.text()) + if t == _('None'): + continue + ks = QKeySequence(t, QKeySequence.NativeText) + if not ks.isEmpty(): + ans.append(ks) + return tuple(ans) + + # }}} class Delegate(QStyledItemDelegate): # {{{ + changed_signal = pyqtSignal() + def __init__(self, parent=None): QStyledItemDelegate.__init__(self, parent) - self.editing_indices = {} + self.editing_index = None + self.closeEditor.connect(self.editing_done) def to_doc(self, index): data = index.data(Qt.UserRole).toPyObject() @@ -181,10 +379,9 @@ class Delegate(QStyledItemDelegate): # {{{ return doc def sizeHint(self, option, index): - if index.row() in self.editing_indices: + if index == self.editing_index: return QSize(200, 200) ans = self.to_doc(index).size().toSize() - #ans.setHeight(ans.height()+10) return ans def paint(self, painter, option, index): @@ -198,34 +395,95 @@ class Delegate(QStyledItemDelegate): # {{{ self.to_doc(index).drawContents(painter) painter.restore() + def createEditor(self, parent, option, index): + w = Editor(parent=parent) + w.editing_done.connect(self.editor_done) + self.editing_index = index + self.sizeHintChanged.emit(index) + return w + + def editor_done(self, editor): + self.commitData.emit(editor) + + def setEditorData(self, editor, index): + all_shortcuts = [x.data for x in index.model().all_shortcuts] + shortcut = index.internalPointer().data + editor.initialize(shortcut, all_shortcuts) + + def setModelData(self, editor, model, index): + self.closeEditor.emit(editor, self.NoHint) + custom_keys = editor.custom_keys + sc = index.data(Qt.UserRole).toPyObject().data + if custom_keys is None: + candidates = [] + for ckey in sc['default_keys']: + ckey = QKeySequence(ckey, QKeySequence.PortableText) + matched = False + for s in editor.all_shortcuts: + for k in s['keys']: + if k == ckey: + matched = True + break + if not matched: + candidates.append(ckey) + candidates = tuple(candidates) + sc['set_to_default'] = True + else: + sc['set_to_default'] = False + candidates = custom_keys + sc['keys'] = candidates + self.changed_signal.emit() + + def updateEditorGeometry(self, editor, option, index): + editor.setGeometry(option.rect) + + def editing_done(self, *args): + idx = self.editing_index + self.editing_index = None + if idx is not None: + self.sizeHintChanged.emit(idx) + # }}} -class ShortcutConfig(QWidget): +class ShortcutConfig(QWidget): # {{{ changed_signal = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) - self._layout = QHBoxLayout() + self._layout = l = QGridLayout() self.setLayout(self._layout) + self.header = QLabel(_('Double click on any entry to change the' + ' keyboard shortcuts associated with it')) + l.addWidget(self.header, 0, 0, 1, 1) self.view = QTreeView(self) self.view.setAlternatingRowColors(True) self.view.setHeaderHidden(True) self.view.setAnimated(True) - self._layout.addWidget(self.view) + l.addWidget(self.view, 1, 0, 1, 1) self.delegate = Delegate() self.view.setItemDelegate(self.delegate) self.delegate.sizeHintChanged.connect(self.scrollTo) + self.delegate.changed_signal.connect(self.changed_signal) + + def restore_defaults(self): + self._model.restore_defaults() + self.changed_signal.emit() + + def commit(self): + self._model.commit() def initialize(self, keyboard): self._model = ConfigModel(keyboard, parent=self) self.view.setModel(self._model) def scrollTo(self, index): - self.view.scrollTo(index) + if index is not None: + self.view.scrollTo(index, self.view.PositionAtCenter) @property def is_editing(self): return self.view.state() == self.view.EditingState +# }}} From 226f444274944c4f0d0fc58796e0b1082f418001 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 13:33:34 -0600 Subject: [PATCH 10/16] When switching libraries, if the library no longer exists, give the user a chance to specify a new location for the library, in case it was moved, before forgetting it. Fixes #822018 (request lookup library) --- src/calibre/gui2/actions/choose_library.py | 73 +++++++++++++++++++--- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/src/calibre/gui2/actions/choose_library.py b/src/calibre/gui2/actions/choose_library.py index 1b369a2f0b..acf935d329 100644 --- a/src/calibre/gui2/actions/choose_library.py +++ b/src/calibre/gui2/actions/choose_library.py @@ -8,13 +8,14 @@ __docformat__ = 'restructuredtext en' import os from functools import partial -from PyQt4.Qt import QMenu, Qt, QInputDialog, QToolButton +from PyQt4.Qt import (QMenu, Qt, QInputDialog, QToolButton, QDialog, + QDialogButtonBox, QGridLayout, QLabel, QLineEdit, QIcon, QSize) from calibre import isbytestring from calibre.constants import filesystem_encoding, iswindows from calibre.utils.config import prefs from calibre.gui2 import (gprefs, warning_dialog, Dispatcher, error_dialog, - question_dialog, info_dialog, open_local_file) + question_dialog, info_dialog, open_local_file, choose_dir) from calibre.library.database2 import LibraryDatabase2 from calibre.gui2.actions import InterfaceAction @@ -76,6 +77,62 @@ class LibraryUsageStats(object): # {{{ self.write_stats() # }}} +class MovedDialog(QDialog): # {{{ + + def __init__(self, stats, location, parent=None): + QDialog.__init__(self, parent) + self.setWindowTitle(_('No library found')) + self._l = l = QGridLayout(self) + self.setLayout(l) + self.stats, self.location = stats, location + + loc = self.oldloc = location.replace('/', os.sep) + self.header = QLabel(_('No existing calibre library was found at %s. ' + 'If the library was moved, select its new location below. ' + 'Otherwise calibre will forget this library.')%loc) + self.header.setWordWrap(True) + ncols = 2 + l.addWidget(self.header, 0, 0, 1, ncols) + self.cl = QLabel('
'+_('New location of this library:')) + l.addWidget(self.cl, 1, 0, 1, ncols) + self.loc = QLineEdit(loc, self) + l.addWidget(self.loc, 2, 0, 1, 1) + self.cd = QToolButton(self) + self.cd.setIcon(QIcon(I('document_open.png'))) + self.cd.clicked.connect(self.choose_dir) + l.addWidget(self.cd, 2, 1, 1, 1) + self.bb = QDialogButtonBox(self) + b = self.bb.addButton(_('Library moved'), self.bb.AcceptRole) + b.setIcon(QIcon(I('ok.png'))) + b = self.bb.addButton(_('Forget library'), self.bb.RejectRole) + b.setIcon(QIcon(I('edit-clear.png'))) + self.bb.accepted.connect(self.accept) + self.bb.rejected.connect(self.reject) + l.addWidget(self.bb, 3, 0, 1, ncols) + self.resize(self.sizeHint() + QSize(100, 50)) + + def choose_dir(self): + d = choose_dir(self, 'library moved choose new loc', + _('New library location'), default_dir=self.oldloc) + if d is not None: + self.loc.setText(d) + + def reject(self): + self.stats.remove(self.location) + QDialog.reject(self) + + def accept(self): + newloc = unicode(self.loc.text()) + if not LibraryDatabase2.exists_at(newloc): + error_dialog(self, _('No library found'), + _('No existing calibre library found at %s')%newloc, + show=True) + return + self.stats.rename(self.location, newloc) + self.newloc = newloc + QDialog.accept(self) +# }}} + class ChooseLibraryAction(InterfaceAction): name = 'Choose Library' @@ -339,14 +396,14 @@ class ChooseLibraryAction(InterfaceAction): loc = location.replace('/', os.sep) exists = self.gui.library_view.model().db.exists_at(loc) if not exists: - warning_dialog(self.gui, _('No library found'), - _('No existing calibre library was found at %s.' - ' It will be removed from the list of known' - ' libraries.')%loc, show=True) - self.stats.remove(location) + d = MovedDialog(self.stats, location, self.gui) + ret = d.exec_() self.build_menus() self.gui.iactions['Copy To Library'].build_menus() - return + if ret == d.Accepted: + loc = d.newloc.replace('/', os.sep) + else: + return prefs['library_path'] = loc #from calibre.utils.mem import memory From b150851a58da81a282dc52d5d0bb5a4cd18a75b2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 13:40:34 -0600 Subject: [PATCH 11/16] ... --- src/calibre/gui2/library/views.py | 2 +- src/calibre/gui2/ui.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index f8838f8ce2..f0f30bdb08 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -719,7 +719,7 @@ class BooksView(QTableView): # {{{ break def set_current_row(self, row, select=True): - if row > -1: + if row > -1 and row < self.model().rowCount(QModelIndex()): h = self.horizontalHeader() logical_indices = list(range(h.count())) logical_indices = [x for x in logical_indices if not diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index c1cc07f56c..928e6c63ab 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -522,6 +522,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.card_a_view.reset() self.card_b_view.reset() self.device_manager.set_current_library_uuid(db.library_id) + self.library_view.set_current_row(0) # Run a garbage collection now so that it does not freeze the # interface later gc.collect() From 563fafdc0b57e63fc6c3c965718b89d6140290fe Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 13:57:53 -0600 Subject: [PATCH 12/16] ... --- src/calibre/gui2/keyboard.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index f2a9f8d886..d0c5823aa7 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -78,6 +78,25 @@ class Manager(QObject): # {{{ def register_shortcut(self, unique_name, name, default_keys=(), description=None, action=None, group=None): + ''' + Register a shortcut with calibre. calibre will manage the shortcut, + automatically resolving conflicts and allowing the user to customize + it. + + :param unique_name: A string that uniquely identifies this shortcut + :param name: A user visible name describing the action performed by + this shortcut + :param default_keys: A tuple of keys that trigger this shortcut. Each + key must be a string. For example: ('Ctrl+A', 'Alt+B', 'C', + 'Shift+Meta_D'). These keys will be assigned to the + shortcut unless there is a conflict. + :param action: A QAction object. The shortcut will cause this QAction + to be triggered. Connect to its triggered signal in your code to + respond to the shortcut. + :param group: A string describing what "group" this shortcut belongs + to. This is used to organize the list of shortcuts when the user is + customizing them. + ''' if unique_name in self.shortcuts: name = self.shortcuts[unique_name]['name'] raise NameConflict('Shortcut for %r already registered by %s'%( From 9b19e1638e0560acfc5d5249d3e35af0dc580eed Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 13:59:15 -0600 Subject: [PATCH 13/16] ... --- src/calibre/gui2/keyboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index d0c5823aa7..a68cb00023 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -88,7 +88,7 @@ class Manager(QObject): # {{{ this shortcut :param default_keys: A tuple of keys that trigger this shortcut. Each key must be a string. For example: ('Ctrl+A', 'Alt+B', 'C', - 'Shift+Meta_D'). These keys will be assigned to the + 'Shift+Meta+D'). These keys will be assigned to the shortcut unless there is a conflict. :param action: A QAction object. The shortcut will cause this QAction to be triggered. Connect to its triggered signal in your code to From f6ac950be2856f6f43930a27e8a1115945dbfd52 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 14:14:26 -0600 Subject: [PATCH 14/16] Ebook viewer: Respond to key presses even when the book display area does not have keyboard focus --- src/calibre/gui2/viewer/documentview.py | 8 +++++++- src/calibre/gui2/viewer/main.py | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index fcd02e5e1b..4661bc4899 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -979,6 +979,11 @@ class DocumentView(QWebView): # {{{ return ret def keyPressEvent(self, event): + if not self.handle_key_press(event): + return QWebView.keyPressEvent(self, event) + + def handle_key_press(self, event): + handled = True key = self.shortcuts.get_match(event) func = self.goto_location_actions.get(key, None) if func is not None: @@ -996,7 +1001,8 @@ class DocumentView(QWebView): # {{{ elif key == 'Right': self.scroll_by(x=15) else: - return QWebView.keyPressEvent(self, event) + handled = False + return handled def resizeEvent(self, event): ret = QWebView.resizeEvent(self, event) diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index 5e3d9908c1..f0c67b0b49 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -755,6 +755,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer): if self.current_index > 0: self.load_path(self.iterator.spine[self.current_index-1], pos=1.0) + def keyPressEvent(self, event): + MainWindow.keyPressEvent(self, event) + if not event.isAccepted(): + if not self.view.handle_key_press(event): + event.ignore() + def __enter__(self): return self From 00e11ca00eb36e8ae5b22e5d4fb0eb93090ad707 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 20:24:57 -0600 Subject: [PATCH 15/16] Add search to shortcuts preferences --- src/calibre/gui2/__init__.py | 4 +- src/calibre/gui2/keyboard.py | 124 +++++++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 6 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 539b768b1d..12e60464f7 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -169,7 +169,9 @@ def _config(): # {{{ c.add_opt('scheduler_search_history', default=[], help='Search history for the recipe scheduler') c.add_opt('plugin_search_history', default=[], - help='Search history for the recipe scheduler') + help='Search history for the plugin preferences') + c.add_opt('shortcuts_search_history', default=[], + help='Search history for the keyboard preferences') c.add_opt('worker_limit', default=6, help=_( 'Maximum number of simultaneous conversion/news download jobs. ' diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index a68cb00023..6f8b217d35 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -18,8 +18,10 @@ from PyQt4.Qt import (QObject, QKeySequence, QAbstractItemModel, QModelIndex, from calibre.utils.config import JSONConfig from calibre.constants import DEBUG from calibre import prints -from calibre.utils.icu import sort_key -from calibre.gui2 import NONE, error_dialog +from calibre.utils.icu import sort_key, lower +from calibre.gui2 import NONE, error_dialog, info_dialog +from calibre.utils.search_query_parser import SearchQueryParser +from calibre.gui2.search_box import SearchBox2 ROOT = QModelIndex() @@ -136,10 +138,11 @@ class Node(object): for child in self.children: yield child -class ConfigModel(QAbstractItemModel): +class ConfigModel(QAbstractItemModel, SearchQueryParser): def __init__(self, keyboard, parent=None): QAbstractItemModel.__init__(self, parent) + SearchQueryParser.__init__(self, ['all']) self.keyboard = keyboard groups = sorted(keyboard.groups, key=sort_key) @@ -232,6 +235,74 @@ class ConfigModel(QAbstractItemModel): kmap[sc['unique_name']] = keys self.keyboard.config['map'] = kmap + def universal_set(self): + ans = set() + for i, group in enumerate(self.data): + ans.add((i, -1)) + for j, sc in enumerate(group.children): + ans.add((i, j)) + return ans + + def get_matches(self, location, query, candidates=None): + if candidates is None: + candidates = self.universal_set() + ans = set([]) + if not query: + return ans + query = lower(query) + for c, p in candidates: + if p < 0: + if query in lower(self.data[c].data): + ans.add((c, p)) + else: + try: + sc = self.data[c].children[p].data + except: + continue + if query in lower(sc['name']): + ans.add((c, p)) + return ans + + def find(self, query): + query = query.strip() + if not query: + return ROOT + matches = self.parse(query) + if not matches: + return ROOT + matches = list(sorted(matches)) + c, p = matches[0] + cat_idx = self.index(c, 0) + if p == -1: + return cat_idx + return self.index(p, 0, cat_idx) + + def find_next(self, idx, query, backwards=False): + query = query.strip() + if not query: + return idx + matches = self.parse(query) + if not matches: + return idx + if idx.parent().isValid(): + loc = (idx.parent().row(), idx.row()) + else: + loc = (idx.row(), -1) + if loc not in matches: + return self.find(query) + if len(matches) == 1: + return ROOT + matches = list(sorted(matches)) + i = matches.index(loc) + if backwards: + ans = i - 1 if i - 1 >= 0 else len(matches)-1 + else: + ans = i + 1 if i + 1 < len(matches) else 0 + + ans = matches[ans] + + return (self.index(ans[0], 0) if ans[1] < 0 else + self.index(ans[1], 0, self.index(ans[0], 0))) # }}} @@ -474,16 +545,28 @@ class ShortcutConfig(QWidget): # {{{ self.setLayout(self._layout) self.header = QLabel(_('Double click on any entry to change the' ' keyboard shortcuts associated with it')) - l.addWidget(self.header, 0, 0, 1, 1) + l.addWidget(self.header, 0, 0, 1, 3) self.view = QTreeView(self) self.view.setAlternatingRowColors(True) self.view.setHeaderHidden(True) self.view.setAnimated(True) - l.addWidget(self.view, 1, 0, 1, 1) + l.addWidget(self.view, 1, 0, 1, 3) self.delegate = Delegate() self.view.setItemDelegate(self.delegate) self.delegate.sizeHintChanged.connect(self.scrollTo) self.delegate.changed_signal.connect(self.changed_signal) + self.search = SearchBox2(self) + self.search.initialize('shortcuts_search_history', + help_text=_('Search for a shortcut by name')) + self.search.search.connect(self.find) + l.addWidget(self.search, 2, 0, 1, 1) + self.nb = QPushButton(QIcon(I('arrow-down.png')), _('&Next'), self) + self.pb = QPushButton(QIcon(I('arrow-up.png')), _('&Previous'), self) + self.nb.clicked.connect(self.find_next) + self.pb.clicked.connect(self.find_previous) + l.addWidget(self.nb, 2, 1, 1, 1) + l.addWidget(self.pb, 2, 2, 1, 1) + l.setColumnStretch(0, 100) def restore_defaults(self): self._model.restore_defaults() @@ -504,5 +587,36 @@ class ShortcutConfig(QWidget): # {{{ def is_editing(self): return self.view.state() == self.view.EditingState + def find(self, query): + idx = self._model.find(query) + if not idx.isValid(): + return info_dialog(self, _('No matches'), + _('Could not find any matching shortcuts'), show=True, + show_copy_button=False) + self.highlight_index(idx) + + def highlight_index(self, idx): + self.view.scrollTo(idx) + self.view.selectionModel().select(idx, + self.view.selectionModel().ClearAndSelect) + self.view.setCurrentIndex(idx) + + def find_next(self, *args): + idx = self.view.currentIndex() + if not idx.isValid(): + idx = self._model.index(0, 0) + idx = self._model.find_next(idx, + unicode(self.search.currentText())) + self.highlight_index(idx) + + def find_previous(self, *args): + idx = self.view.currentIndex() + if not idx.isValid(): + idx = self._model.index(0, 0) + idx = self._model.find_next(idx, + unicode(self.search.currentText()), backwards=True) + self.highlight_index(idx) + + # }}} From 52256a641bd1f0dd57f7f4b4de832520baaaaa17 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 10 Aug 2011 20:54:14 -0600 Subject: [PATCH 16/16] The various options to control how automerging when adding books now also apply when copying a book from one library to another. Fixes #822033 (books lost during moving to other library) --- src/calibre/gui2/actions/copy_to_library.py | 33 +++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py index a70ebdad7b..846eb54b9c 100644 --- a/src/calibre/gui2/actions/copy_to_library.py +++ b/src/calibre/gui2/actions/copy_to_library.py @@ -12,7 +12,7 @@ from threading import Thread from PyQt4.Qt import QToolButton from calibre.gui2.actions import InterfaceAction -from calibre.gui2 import error_dialog, Dispatcher, warning_dialog +from calibre.gui2 import error_dialog, Dispatcher, warning_dialog, gprefs from calibre.gui2.dialogs.progress import ProgressDialog from calibre.utils.config import prefs, tweaks @@ -65,14 +65,37 @@ class Worker(Thread): # {{{ as_path=True) if p: paths.append(p) - added = False + automerged = False if prefs['add_formats_to_existing']: identical_book_list = newdb.find_identical_books(mi) if identical_book_list: # books with same author and nearly same title exist in newdb - added = True + automerged = True + seen_fmts = set() for identical_book in identical_book_list: - self.add_formats(identical_book, paths, newdb, replace=False) - if not added: + ib_fmts = newdb.formats(identical_book, index_is_id=True) + if ib_fmts: + seen_fmts |= set(ib_fmts.split(',')) + replace = gprefs['automerge'] == 'overwrite' + self.add_formats(identical_book, paths, newdb, + replace=replace) + + if gprefs['automerge'] == 'new record': + incoming_fmts = \ + set([os.path.splitext(path)[-1].replace('.', + '').upper() for path in paths]) + + if incoming_fmts.intersection(seen_fmts): + # There was at least one duplicate format + # so create a new record and put the + # incoming formats into it + # We should arguably put only the duplicate + # formats, but no real harm is done by having + # all formats + newdb.import_book(mi, paths, notify=False, import_hooks=False, + apply_import_tags=tweaks['add_new_book_tags_when_importing_books'], + preserve_uuid=False) + + if not automerged: newdb.import_book(mi, paths, notify=False, import_hooks=False, apply_import_tags=tweaks['add_new_book_tags_when_importing_books'], preserve_uuid=self.delete_after)