diff --git a/imgsrc/column.svg b/imgsrc/column.svg
index 4d6f4b809e..ac2f026473 100644
--- a/imgsrc/column.svg
+++ b/imgsrc/column.svg
@@ -1,61 +1,211 @@
-
\ No newline at end of file
diff --git a/imgsrc/drawer.svg b/imgsrc/drawer.svg
index 679bca53b2..22e54a1537 100644
--- a/imgsrc/drawer.svg
+++ b/imgsrc/drawer.svg
@@ -1,2679 +1,2508 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/images/column.png b/resources/images/column.png
index ae26292b25..0a5f184601 100644
Binary files a/resources/images/column.png and b/resources/images/column.png differ
diff --git a/resources/images/drawer.png b/resources/images/drawer.png
index 356de02a88..dd33c2ad6e 100644
Binary files a/resources/images/drawer.png and b/resources/images/drawer.png differ
diff --git a/resources/images/news/journalgazette.png b/resources/images/news/journalgazette.png
new file mode 100644
index 0000000000..f9b3316cab
Binary files /dev/null and b/resources/images/news/journalgazette.png differ
diff --git a/resources/images/news/walrusmag.png b/resources/images/news/walrusmag.png
new file mode 100644
index 0000000000..17030d94b8
Binary files /dev/null and b/resources/images/news/walrusmag.png differ
diff --git a/resources/recipes/buckmasters.recipe b/resources/recipes/buckmasters.recipe
new file mode 100644
index 0000000000..e3d852fa07
--- /dev/null
+++ b/resources/recipes/buckmasters.recipe
@@ -0,0 +1,42 @@
+from calibre.web.feeds.news import BasicNewsRecipe
+from calibre.ebooks.BeautifulSoup import Tag
+
+class AdvancedUserRecipe1282101454(BasicNewsRecipe):
+ title = 'BuckMasters In The Kitchen'
+ language = 'en'
+ __author__ = 'TonytheBookworm & Starson17'
+ description = 'Learn how to cook all those outdoor varments'
+ publisher = 'BuckMasters.com'
+ category = 'food,cooking,recipes'
+ oldest_article = 365
+ max_articles_per_feed = 100
+ conversion_options = {'linearize_tables' : True}
+ masthead_url = 'http://www.buckmasters.com/Portals/_default/Skins/BM_10/images/header_bg.jpg'
+ keep_only_tags = [
+ dict(name='table', attrs={'class':['containermaster_black']})
+ ]
+ remove_tags_after = [dict(name='div', attrs={'align':['left']})]
+ feeds = [
+ ('Recipes', 'http://www.buckmasters.com/DesktopModules/DnnForge%20-%20NewsArticles/RSS.aspx?TabID=292&ModuleID=658&MaxCount=25'),
+ ]
+
+ def preprocess_html(self, soup):
+ item = soup.find('a', attrs={'class':['MenuTopSelected']})
+ if item:
+ item.parent.extract()
+ for img_tag in soup.findAll('img'):
+ parent_tag = img_tag.parent
+ if parent_tag.name == 'a':
+ new_tag = Tag(soup,'p')
+ new_tag.insert(0,img_tag)
+ parent_tag.replaceWith(new_tag)
+ elif parent_tag.name == 'p':
+ if not self.tag_to_string(parent_tag) == '':
+ new_div = Tag(soup,'div')
+ new_tag = Tag(soup,'p')
+ new_tag.insert(0,img_tag)
+ parent_tag.replaceWith(new_div)
+ new_div.insert(0,new_tag)
+ new_div.insert(1,parent_tag)
+ return soup
+
diff --git a/resources/recipes/journalgazette.recipe b/resources/recipes/journalgazette.recipe
new file mode 100644
index 0000000000..406917f5ce
--- /dev/null
+++ b/resources/recipes/journalgazette.recipe
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+__license__ = 'GPL v3'
+__author__ = 'somedayson & TonytheBookworm, revised by Cynthia Clavey'
+__copyright__ = '2010, Cynthia Clavey cynvision@yahoo.com'
+__version__ = '1.02'
+__date__ = '05, september 2010'
+__docformat__ = 'restructuredtext en'
+from calibre.web.feeds.recipes import BasicNewsRecipe
+
+class AdvancedUserRecipe1283666183(BasicNewsRecipe):
+ title = u'Journal Gazette Ft. Wayne IN'
+ __author__ = 'cynvision'
+ oldest_article = 1
+ max_articles_per_feed = 8
+ no_stylesheets = True
+ remove_javascript = True
+ use_embedded_content = False
+ keep_only_tags = [dict(name='div', attrs={'id':'mainContent'})]
+ extra_css = '#copyinfo { font-size: 6 ;} \n #photocredit { font-size: 6 ;} \n .pubinfo { font-size: 6 ;}'
+ masthead_url = 'http://www.journalgazette.net/img/icons/jgmini.gif'
+# cover_url = 'http://www.journalgazette.net/img/icons/jgmini.gif'
+ encoding = 'cp1252'
+
+ feeds = [(u'Opinion', u'http://journalgazette.net/apps/pbcs.dll/section?Category=EDIT&template=blogrss&mime=xml'),
+ (u'Local News',u'http://journalgazette.net/apps/pbcs.dll/section?Category=LOCAL&template=blogrss&mime=xml') ,
+ (u'Sports',u'http://journalgazette.net/apps/pbcs.dll/section?Category=SPORTS&template=blogrss&mime=xml' ),
+ (u'Features',u'http://journalgazette.net/apps/pbcs.dll/section?Category=FEAT&template=blogrss&mime=xml'),
+ (u'Business',u'http://journalgazette.net/apps/pbcs.dll/section?Category=BIZ&template=blogrss&mime=xml'),
+ (u'Ice Chips',u'http://journalgazette.net/apps/pbcs.dll/section?Category=BLOGS11&template=blogrss&mime=xml '),
+ (u'Entertainment',u'http://journalgazette.net/apps/pbcs.dll/section?Category=ENT&template=blogrss&mime=xml'),
+ (u'Food',u'http://journalgazette.net/apps/pbcs.dll/section?Category=FOOD&template=blogrss&mime=xml')
+ ]
+
+
+
+
+ def print_version(self, url):
+ split1 = url.split("/")
+ #print 'THE SPLIT IS: ', split1
+ #url1 = split1[0]
+ #url2 = split1[1]
+ url3 = split1[2]
+ #url4 = split1[3]
+ url5 = split1[4]
+ url6 = split1[5]
+ url7 = split1[6]
+ #url8 = split1[7]
+
+ #need to convert to print_version
+ #originalversion is : http://www.journalgazette.net/article/20100905/EDIT10/309059959/1021/EDIT
+ #printversion should be: http://www.journalgazette.net/apps/pbcs.dll/article?AID=/20100905/EDIT10/309059959/-1/EDIT01&template=printart
+ #results of the split
+ #THE SPLIT IS: [u'http:', u'', u'www.journalgazette.net', u'article', u'20100905', u'EDIT10', u'309059959', u'1021', u'EDIT']
+
+
+
+ print_url = 'http://' + url3 + '/apps/pbcs.dll/article?AID=/' + url5 + '/' + url6 + '/' + url7 + '/-1/EDIT01&template=printart'
+ #print 'THIS URL WILL PRINT: ', print_url # this is a test string to see what the url is it will return
+ return print_url
+
+ def preprocess_html(self, soup):
+ for item in soup.findAll(style=True):
+ del item['style']
+ return soup
diff --git a/resources/recipes/walrusmag.recipe b/resources/recipes/walrusmag.recipe
new file mode 100644
index 0000000000..5c10100fe4
--- /dev/null
+++ b/resources/recipes/walrusmag.recipe
@@ -0,0 +1,46 @@
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class AdvancedUserRecipe1282101454(BasicNewsRecipe):
+ title = 'The Walrus Mag'
+ language = 'en'
+ __author__ = 'TonytheBookworm'
+ description = 'national general interest magazine about Canada and its place in the world'
+ publisher = 'Tony Stegall'
+ category = 'Canada, news'
+ oldest_article = 365
+ max_articles_per_feed = 100
+
+ masthead_url = 'http://www.walrusmagazine.com/images/wordmark.png'
+ keep_only_tags = [
+ dict(name='h1'),
+ dict(name='div', attrs={'id':['prbody']})
+ # ,dict(attrs={'id':['cxArticleText','cxArticleBodyText']})
+ ]
+ feeds = [
+ ('Walrus Magazine', 'http://feeds.feedburner.com/WalrusFeatureArticles?format=xml'),
+
+ ]
+
+
+
+
+ def print_version(self, url):
+ split1 = url.split("/articles/")
+ #print 'THE SPLIT IS: ', split1
+ url1 = split1[0]
+ #print 'url1 is: ',url1
+ url2 = split1[1]
+ #print 'url2 is: ',url2
+
+
+ #need to convert to print_version
+ #originalversion is : http://www.walrusmagazine.com/articles/2010.09-frontier-no-one-can-hear-you-scream/
+ #printversion should be: http://www.walrusmagazine.com/print/2010.09-frontier-no-one-can-hear-you-scream/
+
+
+
+
+ print_url = url1 + '/print/' + url2
+ #print 'THIS URL WILL PRINT: ', print_url # this is a test string to see what the url is it will return
+ return print_url
+
diff --git a/resources/recipes/wsj_free.recipe b/resources/recipes/wsj_free.recipe
new file mode 100644
index 0000000000..7f3664f1c4
--- /dev/null
+++ b/resources/recipes/wsj_free.recipe
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+__license__ = 'GPL v3'
+__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
+__docformat__ = 'restructuredtext en'
+
+from calibre.web.feeds.news import BasicNewsRecipe
+import copy
+
+class WallStreetJournal(BasicNewsRecipe):
+
+ title = 'Wall Street Journal (free)'
+ __author__ = 'Kovid Goyal, Sujata Raman, Joshua Oster-Morris, Starson17'
+ description = 'News and current affairs'
+ language = 'en'
+ cover_url = 'http://dealbreaker.com/images/thumbs/Wall%20Street%20Journal%20A1.JPG'
+ max_articles_per_feed = 1000
+ timefmt = ' [%a, %b %d, %Y]'
+ no_stylesheets = True
+
+ extra_css = '''h1{color:#093D72 ; font-size:large ; font-family:Georgia,"Century Schoolbook","Times New Roman",Times,serif; }
+ h2{color:#474537; font-family:Georgia,"Century Schoolbook","Times New Roman",Times,serif; font-size:small; font-style:italic;}
+ .subhead{color:gray; font-family:Georgia,"Century Schoolbook","Times New Roman",Times,serif; font-size:small; font-style:italic;}
+ .insettipUnit {color:#666666; font-family:Arial,Sans-serif;font-size:xx-small }
+ .targetCaption{ font-size:x-small; color:#333333; font-family:Arial,Helvetica,sans-serif}
+ .article{font-family :Arial,Helvetica,sans-serif; font-size:x-small}
+ .tagline {color:#333333; font-size:xx-small}
+ .dateStamp {color:#666666; font-family:Arial,Helvetica,sans-serif}
+ h3{color:blue ;font-family:Arial,Helvetica,sans-serif; font-size:xx-small}
+ .byline{color:blue;font-family:Arial,Helvetica,sans-serif; font-size:xx-small}
+ h6{color:#333333; font-family:Georgia,"Century Schoolbook","Times New Roman",Times,serif; font-size:small;font-style:italic; }
+ .paperLocation{color:#666666; font-size:xx-small}'''
+
+ remove_tags_before = dict(name='h1')
+ remove_tags = [
+ dict(id=["articleTabs_tab_article", "articleTabs_tab_comments", "articleTabs_tab_interactive","articleTabs_tab_video","articleTabs_tab_map","articleTabs_tab_slideshow"]),
+ {'class':['footer_columns','network','insetCol3wide','interactive','video','slideshow','map','insettip','insetClose','more_in', "insetContent", 'articleTools_bottom', 'aTools', "tooltip", "adSummary", "nav-inline"]},
+ dict(name='div', attrs={'data-flash-settings':True}),
+ {'class':['insetContent embedType-interactive insetCol3wide','insetCol6wide','insettipUnit']},
+ dict(rel='shortcut icon'),
+ ]
+ remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},]
+
+ def postprocess_html(self, soup, first):
+ for tag in soup.findAll(name=['table', 'tr', 'td']):
+ tag.name = 'div'
+
+ for tag in soup.findAll('div', dict(id=["articleThumbnail_1", "articleThumbnail_2", "articleThumbnail_3", "articleThumbnail_4", "articleThumbnail_5", "articleThumbnail_6", "articleThumbnail_7"])):
+ tag.extract()
+
+ return soup
+
+ def wsj_get_index(self):
+ return self.index_to_soup('http://online.wsj.com/itp')
+
+ def wsj_add_feed(self,feeds,title,url):
+ self.log('Found section:', title)
+ if url.endswith('whatsnews'):
+ articles = self.wsj_find_wn_articles(url)
+ else:
+ articles = self.wsj_find_articles(url)
+ if articles:
+ feeds.append((title, articles))
+ return feeds
+
+ def parse_index(self):
+ soup = self.wsj_get_index()
+
+ date = soup.find('span', attrs={'class':'date-date'})
+ if date is not None:
+ self.timefmt = ' [%s]'%self.tag_to_string(date)
+
+ feeds = []
+ div = soup.find('div', attrs={'class':'itpHeader'})
+ div = div.find('ul', attrs={'class':'tab'})
+ for a in div.findAll('a', href=lambda x: x and '/itp/' in x):
+ pageone = a['href'].endswith('pageone')
+ if pageone:
+ title = 'Front Section'
+ url = 'http://online.wsj.com' + a['href']
+ feeds = self.wsj_add_feed(feeds,title,url)
+ title = 'What''s News'
+ url = url.replace('pageone','whatsnews')
+ feeds = self.wsj_add_feed(feeds,title,url)
+ else:
+ title = self.tag_to_string(a)
+ url = 'http://online.wsj.com' + a['href']
+ feeds = self.wsj_add_feed(feeds,title,url)
+ return feeds
+
+ def wsj_find_wn_articles(self, url):
+ soup = self.index_to_soup(url)
+ articles = []
+
+ whats_news = soup.find('div', attrs={'class':lambda x: x and 'whatsNews-simple' in x})
+ if whats_news is not None:
+ for a in whats_news.findAll('a', href=lambda x: x and '/article/' in x):
+ container = a.findParent(['p'])
+ meta = a.find(attrs={'class':'meta_sectionName'})
+ if meta is not None:
+ meta.extract()
+ title = self.tag_to_string(a).strip()
+ url = a['href']
+ desc = ''
+ if container is not None:
+ desc = self.tag_to_string(container)
+
+ articles.append({'title':title, 'url':url,
+ 'description':desc, 'date':''})
+
+ self.log('\tFound WN article:', title)
+
+ return articles
+
+ def wsj_find_articles(self, url):
+ soup = self.index_to_soup(url)
+
+ whats_news = soup.find('div', attrs={'class':lambda x: x and 'whatsNews-simple' in x})
+ if whats_news is not None:
+ whats_news.extract()
+
+ articles = []
+
+ flavorarea = soup.find('div', attrs={'class':lambda x: x and 'ahed' in x})
+ if flavorarea is not None:
+ flavorstory = flavorarea.find('a', href=lambda x: x and x.startswith('/article'))
+ if flavorstory is not None:
+ flavorstory['class'] = 'mjLinkItem'
+ metapage = soup.find('span', attrs={'class':lambda x: x and 'meta_sectionName' in x})
+ if metapage is not None:
+ flavorstory.append( copy.copy(metapage) ) #metapage should always be A1 because that should be first on the page
+
+ for a in soup.findAll('a', attrs={'class':'mjLinkItem'}, href=True):
+ container = a.findParent(['li', 'div'])
+ meta = a.find(attrs={'class':'meta_sectionName'})
+ if meta is not None:
+ meta.extract()
+ title = self.tag_to_string(a).strip() + ' [%s]'%self.tag_to_string(meta)
+ url = 'http://online.wsj.com'+a['href']
+ desc = ''
+ p = container.find('p')
+ if p is not None:
+ desc = self.tag_to_string(p)
+
+ articles.append({'title':title, 'url':url,
+ 'description':desc, 'date':''})
+
+ self.log('\tFound article:', title)
+
+ return articles
+
+ def cleanup(self):
+ self.browser.open('http://online.wsj.com/logout?url=http://online.wsj.com')
+
diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py
index 91052bbc2b..083bc03723 100644
--- a/src/calibre/customize/__init__.py
+++ b/src/calibre/customize/__init__.py
@@ -393,9 +393,16 @@ class PreferencesPlugin(Plugin): # {{{
#: The category name displayed to the user for this plugin
gui_category = None
+
#: The name displayed to the user for this plugin
gui_name = None
+ #: The icon for this plugin, should be an absolute path
+ icon = None
+
+ #: The description used for tooltips and the like
+ description = None
+
def create_widget(self, parent=None):
'''
Create and return the actual Qt widget used for setting this group of
diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index 3be6661ad2..d95a7d1c8a 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -678,133 +678,181 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
class LookAndFeel(PreferencesPlugin):
name = 'Look & Feel'
+ icon = I('lookfeel.png')
gui_name = _('Look and Feel')
category = 'Interface'
gui_category = _('Interface')
category_order = 1
name_order = 1
config_widget = 'calibre.gui2.preferences.look_feel'
+ description = _('Adjust the look and feel of the calibre interface'
+ ' to suit your tastes')
class Behavior(PreferencesPlugin):
name = 'Behavior'
+ icon = I('config.png')
gui_name = _('Behavior')
category = 'Interface'
gui_category = _('Interface')
category_order = 1
name_order = 2
config_widget = 'calibre.gui2.preferences.behavior'
+ description = _('Change the way calibre behaves')
class Columns(PreferencesPlugin):
name = 'Custom Columns'
+ icon = I('column.png')
gui_name = _('Add your own columns')
category = 'Interface'
gui_category = _('Interface')
category_order = 1
name_order = 3
config_widget = 'calibre.gui2.preferences.columns'
+ description = _('Add/remove your own columns to the calibre book list')
class Toolbar(PreferencesPlugin):
name = 'Toolbar'
+ icon = I('wizard.png')
gui_name = _('Customize the toolbar')
category = 'Interface'
gui_category = _('Interface')
category_order = 1
name_order = 4
config_widget = 'calibre.gui2.preferences.toolbar'
+ description = _('Customize the toolbars and context menus, changing which'
+ ' actions are available in each')
class InputOptions(PreferencesPlugin):
name = 'Input Options'
+ icon = I('arrow-down.png')
gui_name = _('Input Options')
category = 'Conversion'
gui_category = _('Conversion')
category_order = 2
name_order = 1
config_widget = 'calibre.gui2.preferences.conversion:InputOptions'
+ description = _('Set conversion options specific to each input format')
class CommonOptions(PreferencesPlugin):
name = 'Common Options'
+ icon = I('convert.png')
gui_name = _('Common Options')
category = 'Conversion'
gui_category = _('Conversion')
category_order = 2
name_order = 2
config_widget = 'calibre.gui2.preferences.conversion:CommonOptions'
+ description = _('Set conversion options common to all formats')
class OutputOptions(PreferencesPlugin):
name = 'Output Options'
+ icon = I('arrow-up.png')
gui_name = _('Output Options')
category = 'Conversion'
gui_category = _('Conversion')
category_order = 2
name_order = 3
config_widget = 'calibre.gui2.preferences.conversion:OutputOptions'
+ description = _('Set conversion options specific to each output format')
class Adding(PreferencesPlugin):
name = 'Adding'
+ icon = I('add_book.png')
gui_name = _('Adding books')
category = 'Import/Export'
gui_category = _('Import/Export')
category_order = 3
name_order = 1
config_widget = 'calibre.gui2.preferences.adding'
+ description = _('Control how calibre reads metadata from files when '
+ 'adding books')
class Saving(PreferencesPlugin):
name = 'Saving'
+ icon = I('save.png')
gui_name = _('Saving books to disk')
category = 'Import/Export'
gui_category = _('Import/Export')
category_order = 3
name_order = 2
config_widget = 'calibre.gui2.preferences.saving'
+ description = _('Control how calibre exports files from its database '
+ 'to disk when using Save to disk')
class Sending(PreferencesPlugin):
name = 'Sending'
+ icon = I('sync.png')
gui_name = _('Sending books to devices')
category = 'Import/Export'
gui_category = _('Import/Export')
category_order = 3
name_order = 3
config_widget = 'calibre.gui2.preferences.sending'
+ description = _('Control how calibre transfers files to your '
+ 'ebook reader')
class Email(PreferencesPlugin):
name = 'Email'
- gui_name = _('Sending books by email')
+ icon = I('mail.png')
+ gui_name = _('Sharing books by email')
category = 'Sharing'
gui_category = _('Sharing')
category_order = 4
name_order = 1
config_widget = 'calibre.gui2.preferences.emailp'
+ description = _('Setup sharing of books via email. Can be used '
+ 'for automatic sending of downloaded news to your devices')
class Server(PreferencesPlugin):
name = 'Server'
+ icon = I('network-server.png')
gui_name = _('Sharing over the net')
category = 'Sharing'
gui_category = _('Sharing')
category_order = 4
name_order = 2
config_widget = 'calibre.gui2.preferences.server'
+ description = _('Setup the calibre Content Server which will '
+ 'give you access to your calibre library from anywhere, '
+ 'on any device, over the internet')
class Plugins(PreferencesPlugin):
name = 'Plugins'
+ icon = I('plugins.png')
gui_name = _('Plugins')
category = 'Advanced'
gui_category = _('Advanced')
category_order = 5
name_order = 1
config_widget = 'calibre.gui2.preferences.plugins'
+ description = _('Add/remove/customize various bits of calibre '
+ 'functionality')
class Tweaks(PreferencesPlugin):
name = 'Tweaks'
+ icon = I('drawer.png')
gui_name = _('Tweaks')
category = 'Advanced'
gui_category = _('Advanced')
category_order = 5
name_order = 2
config_widget = 'calibre.gui2.preferences.tweaks'
+ description = _('Fine tune how calibre behaves in various contexts')
+
+class Misc(PreferencesPlugin):
+ name = 'Misc'
+ icon = I('exec.png')
+ gui_name = _('Miscellaneous')
+ category = 'Advanced'
+ gui_category = _('Advanced')
+ category_order = 5
+ name_order = 3
+ config_widget = 'calibre.gui2.preferences.misc'
+ description = _('Miscellaneous advanced configuration')
plugins += [LookAndFeel, Behavior, Columns, Toolbar, InputOptions,
CommonOptions, OutputOptions, Adding, Saving, Sending, Email, Server,
- Plugins, Tweaks]
+ Plugins, Tweaks, Misc]
#}}}
diff --git a/src/calibre/devices/jetbook/driver.py b/src/calibre/devices/jetbook/driver.py
index 0d2e35e4fc..6ee1c07464 100644
--- a/src/calibre/devices/jetbook/driver.py
+++ b/src/calibre/devices/jetbook/driver.py
@@ -87,7 +87,7 @@ class MIBUK(USBMS):
name = 'MiBuk Wolder Device Interface'
description = _('Communicate with the MiBuk Wolder reader.')
author = 'Kovid Goyal'
- supported_platforms = ['windows', 'osx', 'linux']
+ supported_platforms = ['windows']
FORMATS = ['epub', 'mobi', 'prc', 'fb2', 'txt', 'rtf', 'pdf']
diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py
index e50131afe3..0343c6df84 100644
--- a/src/calibre/gui2/actions/delete.py
+++ b/src/calibre/gui2/actions/delete.py
@@ -159,7 +159,7 @@ class DeleteAction(InterfaceAction):
if self.gui.stack.currentIndex() == 0:
if not confirm('
'+_('The selected books will be '
'permanently deleted and the files '
- 'removed from your computer. Are you sure?')
+ 'removed from your calibre library. Are you sure?')
+'
', 'library_delete_books', self.gui):
return
ci = view.currentIndex()
diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py
index 6b8c303fbe..744ab20d10 100644
--- a/src/calibre/gui2/actions/device.py
+++ b/src/calibre/gui2/actions/device.py
@@ -122,7 +122,7 @@ class ConnectShareAction(InterfaceAction):
self.share_conn_menu.toggle_server.connect(self.toggle_content_server)
self.share_conn_menu.config_email.connect(partial(
self.gui.iactions['Preferences'].do_config,
- initial_category='email'))
+ initial_plugin=('Sharing', 'Email')))
self.qaction.setMenu(self.share_conn_menu)
self.share_conn_menu.connect_to_folder.connect(self.gui.connect_to_folder)
self.share_conn_menu.connect_to_itunes.connect(self.gui.connect_to_itunes)
diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py
index 7a1e589d2a..f0232d9859 100644
--- a/src/calibre/gui2/actions/edit_metadata.py
+++ b/src/calibre/gui2/actions/edit_metadata.py
@@ -51,7 +51,8 @@ class EditMetadataAction(InterfaceAction):
self.merge_books)
mb.addSeparator()
mb.addAction(_('Merge into first selected book - keep others'),
- partial(self.merge_books, safe_merge=True))
+ partial(self.merge_books, safe_merge=True),
+ Qt.AltModifier+Qt.Key_M)
self.merge_menu = mb
self.action_merge.setMenu(mb)
md.addSeparator()
diff --git a/src/calibre/gui2/actions/preferences.py b/src/calibre/gui2/actions/preferences.py
index 9173cd8144..a379698140 100644
--- a/src/calibre/gui2/actions/preferences.py
+++ b/src/calibre/gui2/actions/preferences.py
@@ -8,8 +8,8 @@ __docformat__ = 'restructuredtext en'
from PyQt4.Qt import QIcon, QMenu
from calibre.gui2.actions import InterfaceAction
-from calibre.gui2.dialogs.config import ConfigDialog
-from calibre.gui2 import error_dialog, config
+from calibre.gui2.preferences.main import Preferences
+from calibre.gui2 import error_dialog
class PreferencesAction(InterfaceAction):
@@ -28,7 +28,7 @@ class PreferencesAction(InterfaceAction):
x.triggered.connect(self.do_config)
- def do_config(self, checked=False, initial_category='general'):
+ def do_config(self, checked=False, initial_plugin=None):
if self.gui.job_manager.has_jobs():
d = error_dialog(self.gui, _('Cannot configure'),
_('Cannot configure while there are running jobs.'))
@@ -39,20 +39,12 @@ class PreferencesAction(InterfaceAction):
_('Cannot configure before calibre is restarted.'))
d.exec_()
return
- d = ConfigDialog(self.gui, self.gui.library_view,
- server=self.gui.content_server, initial_category=initial_category)
+ d = Preferences(self.gui, initial_plugin=initial_plugin)
+ d.show()
- d.exec_()
- self.gui.content_server = d.server
- if self.gui.content_server is not None:
- self.gui.content_server.state_callback = \
- self.Dispatcher(self.gui.iactions['Connect Share'].content_server_state_changed)
- self.gui.content_server.state_callback(self.gui.content_server.is_running)
-
- if d.result() == d.Accepted:
- self.gui.search.search_as_you_type(config['search_as_you_type'])
+ if d.committed:
+ self.gui.must_restart_before_config = d.must_restart
self.gui.tags_view.set_new_model() # in case columns changed
- self.gui.iactions['Save To Disk'].reread_prefs()
self.gui.tags_view.recount()
self.gui.create_device_menu()
self.gui.set_device_menu_items_state(bool(self.gui.device_connected))
diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py
deleted file mode 100644
index 067a49de2e..0000000000
--- a/src/calibre/gui2/dialogs/config/__init__.py
+++ /dev/null
@@ -1,1028 +0,0 @@
-__license__ = 'GPL v3'
-__copyright__ = '2008, Kovid Goyal '
-
-import os, re, time, textwrap, copy, sys
-
-from PyQt4.Qt import QDialog, QListWidgetItem, QIcon, \
- QVBoxLayout, QLabel, QPlainTextEdit, \
- QStringListModel, QAbstractItemModel, QFont, \
- SIGNAL, QThread, Qt, QSize, QVariant, QUrl, \
- QModelIndex, QAbstractTableModel, \
- QDialogButtonBox, QTabWidget, QBrush, QLineEdit, \
- QProgressDialog
-
-from calibre.constants import iswindows, isosx
-from calibre.gui2.dialogs.config.config_ui import Ui_Dialog
-from calibre.gui2.dialogs.config.create_custom_column import CreateCustomColumn
-from calibre.gui2.dialogs.config.toolbar import ToolbarLayout
-from calibre.gui2 import error_dialog, config, gprefs, \
- open_url, open_local_file, \
- ALL_COLUMNS, NONE, info_dialog, choose_files, \
- warning_dialog, ResizableDialog, question_dialog
-from calibre.utils.config import prefs, read_raw_tweaks, write_tweaks
-from calibre.ebooks import BOOK_EXTENSIONS
-from calibre.ebooks.oeb.iterator import is_supported
-from calibre.library.server import server_config
-from calibre.customize.ui import initialized_plugins, is_disabled, enable_plugin, \
- disable_plugin, customize_plugin, \
- plugin_customization, add_plugin, \
- remove_plugin, all_input_formats, \
- input_format_plugins, \
- output_format_plugins, available_output_formats
-from calibre.utils.smtp import config as smtp_prefs
-from calibre.gui2.convert import config_widget_for_input_plugin
-from calibre.gui2.convert.look_and_feel import LookAndFeelWidget
-from calibre.gui2.convert.page_setup import PageSetupWidget
-from calibre.gui2.convert.structure_detection import StructureDetectionWidget
-from calibre.ebooks.conversion.plumber import Plumber
-from calibre.utils.logging import Log
-from calibre.gui2.convert.toc import TOCWidget
-from calibre.utils.search_query_parser import saved_searches
-
-
-class ConfigTabs(QTabWidget):
-
- def __init__(self, parent):
- QTabWidget.__init__(self, parent)
- log = Log()
- log.outputs = []
-
- self.plumber = Plumber('dummy.epub', 'dummy.epub', log, dummy=True,
- merge_plugin_recs=False)
-
- def widget_factory(cls):
- return cls(self, self.plumber.get_option_by_name,
- self.plumber.get_option_help, None, None)
-
- lf = widget_factory(LookAndFeelWidget)
- ps = widget_factory(PageSetupWidget)
- sd = widget_factory(StructureDetectionWidget)
- toc = widget_factory(TOCWidget)
-
- self.widgets = [lf, ps, sd, toc]
-
- for plugin in input_format_plugins():
- pw = config_widget_for_input_plugin(plugin)
- if pw is not None:
- pw.ICON = I('forward.png')
- self.widgets.append(widget_factory(pw))
-
- for plugin in output_format_plugins():
- name = plugin.name.lower().replace(' ', '_')
- try:
- output_widget = __import__('calibre.gui2.convert.'+name,
- fromlist=[1])
- pw = output_widget.PluginWidget
- pw.ICON = I('forward.png')
- self.widgets.append(widget_factory(pw))
- except ImportError:
- continue
-
- for i, widget in enumerate(self.widgets):
- self.addTab(widget, widget.TITLE.replace('\n', ' ').replace('&',
- '&&'))
- self.setTabToolTip(i, widget.HELP if widget.HELP else widget.TITLE)
- self.setUsesScrollButtons(True)
-
- def commit(self):
- for widget in self.widgets:
- if not widget.pre_commit_check():
- return False
- widget.commit(save_defaults=True)
- return True
-
-class PluginModel(QAbstractItemModel):
-
- def __init__(self, *args):
- QAbstractItemModel.__init__(self, *args)
- self.icon = QVariant(QIcon(I('plugins.png')))
- p = QIcon(self.icon).pixmap(32, 32, QIcon.Disabled, QIcon.On)
- self.disabled_icon = QVariant(QIcon(p))
- self._p = p
- self.populate()
-
- def populate(self):
- self._data = {}
- for plugin in initialized_plugins():
- if plugin.type not in self._data:
- self._data[plugin.type] = [plugin]
- else:
- self._data[plugin.type].append(plugin)
- self.categories = sorted(self._data.keys())
-
- for plugins in self._data.values():
- plugins.sort(cmp=lambda x, y: cmp(x.name.lower(), y.name.lower()))
-
- def index(self, row, column, parent):
- if not self.hasIndex(row, column, parent):
- return QModelIndex()
-
- if parent.isValid():
- return self.createIndex(row, column, 1+parent.row())
- else:
- return self.createIndex(row, column, 0)
-
- def parent(self, index):
- if not index.isValid() or index.internalId() == 0:
- return QModelIndex()
- return self.createIndex(index.internalId()-1, 0, 0)
-
- def rowCount(self, parent):
- if not parent.isValid():
- return len(self.categories)
- if parent.internalId() == 0:
- category = self.categories[parent.row()]
- return len(self._data[category])
- return 0
-
- def columnCount(self, parent):
- return 1
-
- def index_to_plugin(self, index):
- category = self.categories[index.parent().row()]
- return self._data[category][index.row()]
-
- def plugin_to_index(self, plugin):
- for i, category in enumerate(self.categories):
- parent = self.index(i, 0, QModelIndex())
- for j, p in enumerate(self._data[category]):
- if plugin == p:
- return self.index(j, 0, parent)
- return QModelIndex()
-
- def refresh_plugin(self, plugin, rescan=False):
- if rescan:
- self.populate()
- idx = self.plugin_to_index(plugin)
- self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'), idx, idx)
-
- def flags(self, index):
- if not index.isValid():
- return 0
- if index.internalId() == 0:
- return Qt.ItemIsEnabled
- flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
- return flags
-
- def data(self, index, role):
- if not index.isValid():
- return NONE
- if index.internalId() == 0:
- if role == Qt.DisplayRole:
- category = self.categories[index.row()]
- return QVariant(_("%(plugin_type)s %(plugins)s")%\
- dict(plugin_type=category, plugins=_('plugins')))
- else:
- plugin = self.index_to_plugin(index)
- if role == Qt.DisplayRole:
- ver = '.'.join(map(str, plugin.version))
- desc = '\n'.join(textwrap.wrap(plugin.description, 50))
- ans='%s (%s) %s %s\n%s'%(plugin.name, ver, _('by'), plugin.author, desc)
- c = plugin_customization(plugin)
- if c:
- ans += _('\nCustomization: ')+c
- return QVariant(ans)
- if role == Qt.DecorationRole:
- return self.disabled_icon if is_disabled(plugin) else self.icon
- if role == Qt.ForegroundRole and is_disabled(plugin):
- return QVariant(QBrush(Qt.gray))
- if role == Qt.UserRole:
- return plugin
- return NONE
-
-
-
-class CategoryModel(QStringListModel):
-
- CATEGORIES = [
- ('general', _('General'), 'dialog_information.png'),
- ('interface', _('Interface'), 'lookfeel.png'),
- ('conversion', _('Conversion'), 'convert.png'),
- ('email', _('Email\nDelivery'), 'mail.png'),
- ('add/save', _('Add/Save'), 'save.png'),
- ('advanced', _('Advanced'), 'view.png'),
- ('server', _('Content\nServer'), 'network-server.png'),
- ('plugins', _('Plugins'), 'plugins.png'),
- ]
-
- def __init__(self, *args):
- QStringListModel.__init__(self, *args)
- self.setStringList([x[1] for x in self.CATEGORIES])
-
- def data(self, index, role):
- if role == Qt.DecorationRole:
- return QVariant(QIcon(I(self.CATEGORIES[index.row()][2])))
- return QStringListModel.data(self, index, role)
-
- def index_for_name(self, name):
- for i, x in enumerate(self.CATEGORIES):
- if x[0] == name:
- return self.index(i)
- return self.index(0)
-
-class EmailAccounts(QAbstractTableModel):
-
- def __init__(self, accounts):
- QAbstractTableModel.__init__(self)
- self.accounts = accounts
- self.account_order = sorted(self.accounts.keys())
- self.headers = map(QVariant, [_('Email'), _('Formats'), _('Auto send')])
- self.default_font = QFont()
- self.default_font.setBold(True)
- self.default_font = QVariant(self.default_font)
- self.tooltips =[NONE] + map(QVariant,
- [_('Formats to email. The first matching format will be sent.'),
- '
'+_('If checked, downloaded news will be automatically '
- 'mailed to this email address '
- '(provided it is in one of the listed formats).')])
-
- def rowCount(self, *args):
- return len(self.account_order)
-
- def columnCount(self, *args):
- return 3
-
- def headerData(self, section, orientation, role):
- if role == Qt.DisplayRole and orientation == Qt.Horizontal:
- return self.headers[section]
- return NONE
-
- def data(self, index, role):
- row, col = index.row(), index.column()
- if row < 0 or row >= self.rowCount():
- return NONE
- account = self.account_order[row]
- if role == Qt.UserRole:
- return (account, self.accounts[account])
- if role == Qt.ToolTipRole:
- return self.tooltips[col]
- if role in [Qt.DisplayRole, Qt.EditRole]:
- if col == 0:
- return QVariant(account)
- if col == 1:
- return QVariant(self.accounts[account][0])
- if role == Qt.FontRole and self.accounts[account][2]:
- return self.default_font
- if role == Qt.CheckStateRole and col == 2:
- return QVariant(Qt.Checked if self.accounts[account][1] else Qt.Unchecked)
- return NONE
-
- def flags(self, index):
- if index.column() == 2:
- return QAbstractTableModel.flags(self, index)|Qt.ItemIsUserCheckable
- else:
- return QAbstractTableModel.flags(self, index)|Qt.ItemIsEditable
-
- def setData(self, index, value, role):
- if not index.isValid():
- return False
- row, col = index.row(), index.column()
- account = self.account_order[row]
- if col == 2:
- self.accounts[account][1] ^= True
- elif col == 1:
- self.accounts[account][0] = unicode(value.toString()).upper()
- else:
- na = unicode(value.toString())
- from email.utils import parseaddr
- addr = parseaddr(na)[-1]
- if not addr:
- return False
- self.accounts[na] = self.accounts.pop(account)
- self.account_order[row] = na
- if '@kindle.com' in addr:
- self.accounts[na][0] = 'AZW, MOBI, TPZ, PRC, AZW1'
-
- self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'),
- self.index(index.row(), 0), self.index(index.row(), 2))
- return True
-
- def make_default(self, index):
- if index.isValid():
- row = index.row()
- for x in self.accounts.values():
- x[2] = False
- self.accounts[self.account_order[row]][2] = True
- self.reset()
-
- def add(self):
- x = _('new email address')
- y = x
- c = 0
- while y in self.accounts:
- c += 1
- y = x + str(c)
- auto_send = len(self.accounts) < 1
- self.accounts[y] = ['MOBI, EPUB', auto_send,
- len(self.account_order) == 0]
- self.account_order = sorted(self.accounts.keys())
- self.reset()
- return self.index(self.account_order.index(y), 0)
-
- def remove(self, index):
- if index.isValid():
- row = index.row()
- account = self.account_order[row]
- self.accounts.pop(account)
- self.account_order = sorted(self.accounts.keys())
- has_default = False
- for account in self.account_order:
- if self.accounts[account][2]:
- has_default = True
- break
- if not has_default and self.account_order:
- self.accounts[self.account_order[0]][2] = True
-
- self.reset()
-
-
-class ConfigDialog(ResizableDialog, Ui_Dialog):
-
- def category_current_changed(self, n, p):
- self.stackedWidget.setCurrentIndex(n.row())
-
- def __init__(self, parent, library_view, server=None,
- initial_category='general'):
- ResizableDialog.__init__(self, parent)
- self._category_model = CategoryModel()
-
- self.category_view.currentChanged = self.category_current_changed
- self.category_view.setModel(self._category_model)
- self.parent = parent
- self.library_view = library_view
- self.model = library_view.model()
- self.db = self.model.db
- self.server = server
- self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact)
-
- input_map = prefs['input_format_order']
- all_formats = set()
- for fmt in all_input_formats().union(set(['ZIP', 'RAR'])):
- all_formats.add(fmt.upper())
- for format in input_map + list(all_formats.difference(input_map)):
- item = QListWidgetItem(format, self.input_order)
- item.setData(Qt.UserRole, QVariant(format))
- item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable)
-
- self.connect(self.input_up, SIGNAL('clicked()'), self.up_input)
- self.connect(self.input_down, SIGNAL('clicked()'), self.down_input)
-
- rn = config['use_roman_numerals_for_series_number']
- self.timeout.setValue(prefs['network_timeout'])
- self.roman_numerals.setChecked(rn)
- self.new_version_notification.setChecked(config['new_version_notification'])
-
- # Set up columns
- colmap = list(self.model.column_map)
- state = self.library_view.get_state()
- hidden_cols = state['hidden_columns']
- positions = state['column_positions']
- colmap.sort(cmp=lambda x,y: cmp(positions[x], positions[y]))
- self.custcols = copy.deepcopy(self.db.field_metadata.get_custom_field_metadata())
- for col in colmap:
- item = QListWidgetItem(self.model.headers[col], self.columns)
- item.setData(Qt.UserRole, QVariant(col))
- flags = Qt.ItemIsEnabled|Qt.ItemIsSelectable
- if col != 'ondevice':
- flags |= Qt.ItemIsUserCheckable
- item.setFlags(flags)
- if col != 'ondevice':
- item.setCheckState(Qt.Unchecked if col in hidden_cols else
- Qt.Checked)
- self.column_up.clicked.connect(self.up_column)
- self.column_down.clicked.connect(self.down_column)
- self.del_custcol_button.clicked.connect(self.del_custcol)
- self.add_custcol_button.clicked.connect(self.add_custcol)
- self.edit_custcol_button.clicked.connect(self.edit_custcol)
-
- output_formats = sorted(available_output_formats())
- output_formats.remove('oeb')
- for f in output_formats:
- self.output_format.addItem(f.upper())
- default_index = \
- self.output_format.findText(prefs['output_format'].upper())
- self.output_format.setCurrentIndex(default_index if default_index != -1 else 0)
-
-
- self.cover_browse.setValue(config['cover_flow_queue_length'])
- self.systray_notifications.setChecked(not config['disable_tray_notification'])
- from calibre.utils.localization import available_translations, \
- get_language, get_lang
- lang = get_lang()
- if lang is None or lang not in available_translations():
- lang = 'en'
- self.language.addItem(get_language(lang), QVariant(lang))
- items = [(l, get_language(l)) for l in available_translations() \
- if l != lang]
- if lang != 'en':
- items.append(('en', get_language('en')))
- items.sort(cmp=lambda x, y: cmp(x[1], y[1]))
- for item in items:
- self.language.addItem(item[1], QVariant(item[0]))
-
- exts = set([])
- for ext in BOOK_EXTENSIONS:
- ext = ext.lower()
- ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext)
- if ext == 'lrf' or is_supported('book.'+ext):
- exts.add(ext)
-
- for ext in sorted(exts):
- self.viewer.addItem(ext.upper())
- self.viewer.item(self.viewer.count()-1).setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable)
- self.viewer.item(self.viewer.count()-1).setCheckState(Qt.Checked if ext.upper() in config['internally_viewed_formats'] else Qt.Unchecked)
- self.viewer.sortItems()
- self.start.setEnabled(not getattr(self.server, 'is_running', False))
- self.test.setEnabled(not self.start.isEnabled())
- self.stop.setDisabled(self.start.isEnabled())
- self.connect(self.start, SIGNAL('clicked()'), self.start_server)
- self.connect(self.view_logs, SIGNAL('clicked()'), self.view_server_logs)
- self.connect(self.stop, SIGNAL('clicked()'), self.stop_server)
- self.connect(self.test, SIGNAL('clicked()'), self.test_server)
- self.connect(self.show_server_password, SIGNAL('stateChanged(int)'),
- lambda s: self.password.setEchoMode(self.password.Normal if s == Qt.Checked else self.password.Password))
- self.password.setEchoMode(self.password.Password)
- opts = server_config().parse()
- self.max_cover_size.setText(opts.max_cover)
- self.port.setValue(opts.port)
- self.username.setText(opts.username)
- self.password.setText(opts.password if opts.password else '')
- self.opt_max_opds_items.setValue(opts.max_opds_items)
- self.opt_max_opds_ungrouped_items.setValue(opts.max_opds_ungrouped_items)
- self.auto_launch.setChecked(config['autolaunch_server'])
- self.systray_icon.setChecked(config['systray_icon'])
- self.sync_news.setChecked(config['upload_news_to_device'])
- self.delete_news.setChecked(config['delete_news_from_library_on_upload'])
- p = {'normal':0, 'high':1, 'low':2}[prefs['worker_process_priority']]
- self.priority.setCurrentIndex(p)
- self.priority.setVisible(iswindows)
- self.priority_label.setVisible(iswindows)
- self.new_book_tags.setText(', '.join(prefs['new_book_tags']))
- self._plugin_model = PluginModel()
- self.plugin_view.setModel(self._plugin_model)
- self.plugin_view.setStyleSheet(
- "QTreeView::item { padding-bottom: 10px;}")
- self.connect(self.toggle_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='toggle'))
- self.connect(self.customize_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='customize'))
- self.connect(self.remove_plugin, SIGNAL('clicked()'), lambda : self.modify_plugin(op='remove'))
- self.connect(self.button_plugin_browse, SIGNAL('clicked()'), self.find_plugin)
- self.connect(self.button_plugin_add, SIGNAL('clicked()'), self.add_plugin)
- self.connect(self.button_osx_symlinks, SIGNAL('clicked()'),
- self.create_symlinks)
- self.button_osx_symlinks.setVisible(isosx)
- self.separate_cover_flow.setChecked(config['separate_cover_flow'])
- self.setup_email_page()
- self.delete_news.setEnabled(bool(self.sync_news.isChecked()))
- self.connect(self.sync_news, SIGNAL('toggled(bool)'),
- self.delete_news.setEnabled)
- self.setup_conversion_options()
- self.opt_worker_limit.setValue(config['worker_limit'])
- self.connect(self.button_open_config_dir, SIGNAL('clicked()'),
- self.open_config_dir)
- self.opt_get_social_metadata.setChecked(config['get_social_metadata'])
- self.opt_overwrite_author_title_metadata.setChecked(config['overwrite_author_title_metadata'])
- self.opt_enforce_cpu_limit.setChecked(config['enforce_cpu_limit'])
- self.device_detection_button.clicked.connect(self.debug_device_detection)
- self.port.editingFinished.connect(self.check_port_value)
- self.search_as_you_type.setChecked(config['search_as_you_type'])
- self.show_avg_rating.setChecked(config['show_avg_rating'])
- self.show_splash_screen.setChecked(gprefs.get('show_splash_screen',
- True))
- li = None
- for i, z in enumerate([('wide', _('Wide')),
- ('narrow', _('Narrow'))]):
- x, y = z
- self.opt_gui_layout.addItem(y, QVariant(x))
- if x == config['gui_layout']:
- li = i
- self.opt_gui_layout.setCurrentIndex(li)
- restrictions = sorted(saved_searches().names(),
- cmp=lambda x,y: cmp(x.lower(), y.lower()))
- restrictions.insert(0, '')
- for x in ('gui', 'cs'):
- w = getattr(self, 'opt_%s_restriction'%x)
- w.addItems(restrictions)
- idx = w.findText(self.db.prefs.get(x+'_restriction', ''))
- w.setCurrentIndex(0 if idx < 0 else idx)
- self.opt_disable_animations.setChecked(config['disable_animations'])
- idx = 0
- for i, x in enumerate([(_('Small'), 'small'), (_('Medium'), 'medium'),
- (_('Large'), 'large')]):
- if x[1] == gprefs.get('toolbar_icon_size', 'medium'):
- idx = i
- self.opt_toolbar_icon_size.addItem(x[0], x[1])
- self.opt_toolbar_icon_size.setCurrentIndex(idx)
- idx = 0
- for i, x in enumerate([(_('Automatic'), 'auto'), (_('Always'), 'always'),
- (_('Never'), 'never')]):
- if x[1] == gprefs.get('toolbar_text', 'auto'):
- idx = i
- self.opt_toolbar_text.addItem(x[0], x[1])
- self.opt_toolbar_text.setCurrentIndex(idx)
- self.reset_confirmation_button.clicked.connect(self.reset_confirmation)
-
- deft, curt = read_raw_tweaks()
- self.current_tweaks.setPlainText(curt.decode('utf-8'))
- self.default_tweaks.setPlainText(deft.decode('utf-8'))
- self.restore_tweaks_to_default_button.clicked.connect(self.restore_tweaks_to_default)
- self.toolbar_cm_widget = ToolbarLayout(parent, parent)
- self.toolbar_cm_tab.addTab(self.toolbar_cm_widget,
- _('Toolbars/Context menus'))
-
- self.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category))
-
- def restore_tweaks_to_default(self, *args):
- deft, curt = read_raw_tweaks()
- self.current_tweaks.setPlainText(deft.decode('utf-8'))
-
-
- def reset_confirmation(self):
- from calibre.gui2 import dynamic
- for key in dynamic.keys():
- if key.endswith('_again') and dynamic[key] is False:
- dynamic[key] = True
- info_dialog(self, _('Done'),
- _('Confirmation dialogs have all been reset'), show=True)
-
- def check_port_value(self, *args):
- port = self.port.value()
- if port < 1025:
- warning_dialog(self, _('System port selected'), '
'+
- _('The value %d you have chosen for the content '
- 'server port is a system port. Your operating '
- 'system may not allow the server to run on this '
- 'port. To be safe choose a port number larger than '
- '1024.')%port, show=True)
-
- def debug_device_detection(self):
- from calibre.gui2.dialogs.config.device_debug import DebugDevice
- d = DebugDevice(self)
- d.exec_()
-
- def open_config_dir(self):
- from calibre.utils.config import config_dir
- open_local_file(config_dir)
-
- def create_symlinks(self):
- from calibre.utils.osx_symlinks import create_symlinks
- loc, paths = create_symlinks()
- if loc is None:
- error_dialog(self, _('Error'),
- _('Failed to install command line tools.'),
- det_msg=paths, show=True)
- else:
- info_dialog(self, _('Command line tools installed'),
- '
'+_('Command line tools installed in')+' '+loc+
- ' '+ _('If you move calibre.app, you have to re-install '
- 'the command line tools.'),
- det_msg='\n'.join(paths), show=True)
-
- def setup_conversion_options(self):
- self.conversion_options = ConfigTabs(self)
- self.stackedWidget.insertWidget(2, self.conversion_options)
-
- def setup_email_page(self):
- def x():
- if self._email_accounts.account_order:
- return self._email_accounts.account_order[0]
- self.send_email_widget.initialize(x)
- opts = self.send_email_widget.smtp_opts
- self._email_accounts = EmailAccounts(opts.accounts)
- self.email_view.setModel(self._email_accounts)
-
- self.connect(self.email_add, SIGNAL('clicked(bool)'),
- self.add_email_account)
- self.connect(self.email_make_default, SIGNAL('clicked(bool)'),
- lambda c: self._email_accounts.make_default(self.email_view.currentIndex()))
- self.email_view.resizeColumnsToContents()
- self.connect(self.email_remove, SIGNAL('clicked()'),
- self.remove_email_account)
-
- def add_email_account(self, checked):
- index = self._email_accounts.add()
- self.email_view.setCurrentIndex(index)
- self.email_view.resizeColumnsToContents()
- self.email_view.edit(index)
-
- def remove_email_account(self, *args):
- idx = self.email_view.currentIndex()
- self._email_accounts.remove(idx)
-
- def set_email_settings(self):
- to_set = bool(self._email_accounts.accounts)
- if not self.send_email_widget.set_email_settings(to_set):
- return False
- conf = smtp_prefs()
- conf.set('accounts', self._email_accounts.accounts)
- return True
-
-
- def add_plugin(self):
- path = unicode(self.plugin_path.text())
- if path and os.access(path, os.R_OK) and path.lower().endswith('.zip'):
- add_plugin(path)
- self._plugin_model.populate()
- self._plugin_model.reset()
- else:
- error_dialog(self, _('No valid plugin path'),
- _('%s is not a valid plugin path')%path).exec_()
-
- def find_plugin(self):
- path = choose_files(self, 'choose plugin dialog', _('Choose plugin'),
- filters=[('Plugins', ['zip'])], all_files=False,
- select_only_single_file=True)
- if path:
- self.plugin_path.setText(path[0])
-
- def modify_plugin(self, op=''):
- index = self.plugin_view.currentIndex()
- if index.isValid():
- plugin = self._plugin_model.index_to_plugin(index)
- if op == 'toggle':
- if not plugin.can_be_disabled:
- error_dialog(self,_('Plugin cannot be disabled'),
- _('The plugin: %s cannot be disabled')%plugin.name).exec_()
- return
- if is_disabled(plugin):
- enable_plugin(plugin)
- else:
- disable_plugin(plugin)
- self._plugin_model.refresh_plugin(plugin)
- if op == 'customize':
- if not plugin.is_customizable():
- info_dialog(self, _('Plugin not customizable'),
- _('Plugin: %s does not need customization')%plugin.name).exec_()
- return
- config_dialog = QDialog(self)
- button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
- v = QVBoxLayout(config_dialog)
-
- config_dialog.connect(button_box, SIGNAL('accepted()'), config_dialog.accept)
- config_dialog.connect(button_box, SIGNAL('rejected()'), config_dialog.reject)
- config_dialog.setWindowTitle(_('Customize') + ' ' + plugin.name)
-
- if hasattr(plugin, 'config_widget'):
- config_widget = plugin.config_widget()
- v.addWidget(config_widget)
- v.addWidget(button_box)
- config_dialog.exec_()
-
- if config_dialog.result() == QDialog.Accepted:
- plugin.save_settings(config_widget)
- self._plugin_model.refresh_plugin(plugin)
- else:
- help_text = plugin.customization_help(gui=True)
- help_text = QLabel(help_text, config_dialog)
- help_text.setWordWrap(True)
- help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse
- | Qt.LinksAccessibleByKeyboard)
- help_text.setOpenExternalLinks(True)
- v.addWidget(help_text)
- sc = plugin_customization(plugin)
- if not sc:
- sc = ''
- sc = sc.strip()
- sc = QLineEdit(sc, config_dialog)
- v.addWidget(sc)
- v.addWidget(button_box)
- config_dialog.exec_()
-
- if config_dialog.result() == QDialog.Accepted:
- sc = unicode(sc.text()).strip()
- customize_plugin(plugin, sc)
-
- self._plugin_model.refresh_plugin(plugin)
- elif op == 'remove':
- if remove_plugin(plugin):
- self._plugin_model.populate()
- self._plugin_model.reset()
- else:
- error_dialog(self, _('Cannot remove builtin plugin'),
- plugin.name + _(' cannot be removed. It is a '
- 'builtin plugin. Try disabling it instead.')).exec_()
-
- def up_input(self):
- idx = self.input_order.currentRow()
- if idx > 0:
- self.input_order.insertItem(idx-1, self.input_order.takeItem(idx))
- self.input_order.setCurrentRow(idx-1)
-
- def set_tweaks(self):
- raw = unicode(self.current_tweaks.toPlainText()).encode('utf-8')
- try:
- exec raw
- except:
- import traceback
- error_dialog(self, _('Invalid tweaks'),
- _('The tweaks you entered are invalid, try resetting the'
- ' tweaks to default and changing them one by one until'
- ' you find the invalid setting.'),
- det_msg=traceback.format_exc(), show=True)
- return False
- write_tweaks(raw)
- return True
-
- def down_input(self):
- idx = self.input_order.currentRow()
- if idx < self.input_order.count()-1:
- self.input_order.insertItem(idx+1, self.input_order.takeItem(idx))
- self.input_order.setCurrentRow(idx+1)
-
- # Column settings {{{
- def up_column(self):
- idx = self.columns.currentRow()
- if idx > 0:
- self.columns.insertItem(idx-1, self.columns.takeItem(idx))
- self.columns.setCurrentRow(idx-1)
-
- def down_column(self):
- idx = self.columns.currentRow()
- if idx < self.columns.count()-1:
- self.columns.insertItem(idx+1, self.columns.takeItem(idx))
- self.columns.setCurrentRow(idx+1)
-
- def del_custcol(self):
- idx = self.columns.currentRow()
- if idx < 0:
- return error_dialog(self, '', _('You must select a column to delete it'),
- show=True)
- col = unicode(self.columns.item(idx).data(Qt.UserRole).toString())
- if col not in self.custcols:
- return error_dialog(self, '',
- _('The selected column is not a custom column'), show=True)
- if not question_dialog(self, _('Are you sure?'),
- _('Do you really want to delete column %s and all its data?') %
- self.custcols[col]['name'], show_copy_button=False):
- return
- self.columns.item(idx).setCheckState(False)
- self.columns.takeItem(idx)
- self.custcols[col]['*deleteme'] = True
- return
-
- def add_custcol(self):
- CreateCustomColumn(self, False, self.model.orig_headers, ALL_COLUMNS)
-
- def edit_custcol(self):
- CreateCustomColumn(self, True, self.model.orig_headers, ALL_COLUMNS)
-
- def apply_custom_column_changes(self):
- config_cols = [unicode(self.columns.item(i).data(Qt.UserRole).toString())\
- for i in range(self.columns.count())]
- if not config_cols:
- config_cols = ['title']
- removed_cols = set(self.model.column_map) - set(config_cols)
- hidden_cols = set([unicode(self.columns.item(i).data(Qt.UserRole).toString())\
- for i in range(self.columns.count()) \
- if self.columns.item(i).checkState()==Qt.Unchecked])
- hidden_cols = hidden_cols.union(removed_cols) # Hide removed cols
- hidden_cols = list(hidden_cols.intersection(set(self.model.column_map)))
- if 'ondevice' in hidden_cols:
- hidden_cols.remove('ondevice')
- def col_pos(x, y):
- xidx = config_cols.index(x) if x in config_cols else sys.maxint
- yidx = config_cols.index(y) if y in config_cols else sys.maxint
- return cmp(xidx, yidx)
- positions = {}
- for i, col in enumerate((sorted(self.model.column_map, cmp=col_pos))):
- positions[col] = i
- state = {'hidden_columns': hidden_cols, 'column_positions':positions}
- self.library_view.apply_state(state)
- self.library_view.save_state()
-
- must_restart = False
- for c in self.custcols:
- if self.custcols[c]['colnum'] is None:
- self.db.create_custom_column(
- label=self.custcols[c]['label'],
- name=self.custcols[c]['name'],
- datatype=self.custcols[c]['datatype'],
- is_multiple=self.custcols[c]['is_multiple'],
- display = self.custcols[c]['display'])
- must_restart = True
- elif '*deleteme' in self.custcols[c]:
- self.db.delete_custom_column(label=self.custcols[c]['label'])
- must_restart = True
- elif '*edited' in self.custcols[c]:
- cc = self.custcols[c]
- self.db.set_custom_column_metadata(cc['colnum'], name=cc['name'],
- label=cc['label'],
- display = self.custcols[c]['display'])
- if '*must_restart' in self.custcols[c]:
- must_restart = True
- return must_restart
- # }}}
-
- def view_server_logs(self):
- from calibre.library.server import log_access_file, log_error_file
- d = QDialog(self)
- d.resize(QSize(800, 600))
- layout = QVBoxLayout()
- d.setLayout(layout)
- layout.addWidget(QLabel(_('Error log:')))
- el = QPlainTextEdit(d)
- layout.addWidget(el)
- try:
- el.setPlainText(open(log_error_file, 'rb').read().decode('utf8', 'replace'))
- except IOError:
- el.setPlainText('No error log found')
- layout.addWidget(QLabel(_('Access log:')))
- al = QPlainTextEdit(d)
- layout.addWidget(al)
- try:
- al.setPlainText(open(log_access_file, 'rb').read().decode('utf8', 'replace'))
- except IOError:
- al.setPlainText('No access log found')
- bx = QDialogButtonBox(QDialogButtonBox.Ok)
- layout.addWidget(bx)
- self.connect(bx, SIGNAL('accepted()'), d.accept)
- d.show()
-
- def set_server_options(self):
- c = server_config()
- c.set('port', self.port.value())
- c.set('username', unicode(self.username.text()).strip())
- p = unicode(self.password.text()).strip()
- if not p:
- p = None
- c.set('password', p)
-
- def start_server(self):
- self.set_server_options()
- from calibre.library.server.main import start_threaded_server
- self.server = start_threaded_server(self.db, server_config().parse())
- while not self.server.is_running and self.server.exception is None:
- time.sleep(1)
- if self.server.exception is not None:
- error_dialog(self, _('Failed to start content server'),
- unicode(self.server.exception)).exec_()
- return
- self.start.setEnabled(False)
- self.test.setEnabled(True)
- self.stop.setEnabled(True)
-
- def stop_server(self):
- from calibre.library.server.main import stop_threaded_server
- stop_threaded_server(self.server)
- self.server = None
- self.start.setEnabled(True)
- self.test.setEnabled(False)
- self.stop.setEnabled(False)
-
- def test_server(self):
- open_url(QUrl('http://127.0.0.1:'+str(self.port.value())))
-
- def compact(self, toggled):
- d = CheckIntegrity(self.db, self)
- d.exec_()
-
- def accept(self):
- mcs = unicode(self.max_cover_size.text()).strip()
- if not re.match(r'\d+x\d+', mcs):
- error_dialog(self, _('Invalid size'),
- _('The size %s is invalid. must be of the form widthxheight')%mcs).exec_()
- return
- if not self.set_email_settings():
- return
- if not self.conversion_options.commit():
- return
- if not self.add_save.save_settings():
- return
- if not self.set_tweaks():
- return
- wl = self.opt_worker_limit.value()
- if wl%2 != 0:
- wl += 1
- self.toolbar_cm_widget.commit()
- config['worker_limit'] = wl
-
- config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked())
- config['new_version_notification'] = bool(self.new_version_notification.isChecked())
- prefs['network_timeout'] = int(self.timeout.value())
- input_cols = [unicode(self.input_order.item(i).data(Qt.UserRole).toString()) for i in range(self.input_order.count())]
- prefs['input_format_order'] = input_cols
-
- must_restart = self.apply_custom_column_changes()
-
- config['separate_cover_flow'] = bool(self.separate_cover_flow.isChecked())
- config['disable_tray_notification'] = not self.systray_notifications.isChecked()
- p = {0:'normal', 1:'high', 2:'low'}[self.priority.currentIndex()]
- prefs['worker_process_priority'] = p
- nbt = [x.strip() for x in
- unicode(self.new_book_tags.text()).strip().split(',')]
- prefs['new_book_tags'] = [x for x in nbt if x]
- prefs['output_format'] = unicode(self.output_format.currentText()).upper()
- config['cover_flow_queue_length'] = self.cover_browse.value()
- prefs['language'] = str(self.language.itemData(self.language.currentIndex()).toString())
- config['systray_icon'] = self.systray_icon.checkState() == Qt.Checked
- config['autolaunch_server'] = self.auto_launch.isChecked()
- sc = server_config()
- sc.set('username', unicode(self.username.text()).strip())
- sc.set('password', unicode(self.password.text()).strip())
- sc.set('port', self.port.value())
- sc.set('max_cover', mcs)
- sc.set('max_opds_items', self.opt_max_opds_items.value())
- sc.set('max_opds_ungrouped_items',
- self.opt_max_opds_ungrouped_items.value())
- config['delete_news_from_library_on_upload'] = self.delete_news.isChecked()
- config['upload_news_to_device'] = self.sync_news.isChecked()
- config['search_as_you_type'] = self.search_as_you_type.isChecked()
- config['show_avg_rating'] = self.show_avg_rating.isChecked()
- config['get_social_metadata'] = self.opt_get_social_metadata.isChecked()
- config['overwrite_author_title_metadata'] = self.opt_overwrite_author_title_metadata.isChecked()
- config['enforce_cpu_limit'] = bool(self.opt_enforce_cpu_limit.isChecked())
- config['disable_animations'] = bool(self.opt_disable_animations.isChecked())
- gprefs['show_splash_screen'] = bool(self.show_splash_screen.isChecked())
- for x in ('toolbar_icon_size', 'toolbar_text'):
- w = getattr(self, 'opt_'+x)
- data = w.itemData(w.currentIndex()).toString()
- gprefs[x] = unicode(data)
- fmts = []
- for i in range(self.viewer.count()):
- if self.viewer.item(i).checkState() == Qt.Checked:
- fmts.append(str(self.viewer.item(i).text()))
- config['internally_viewed_formats'] = fmts
- val = self.opt_gui_layout.itemData(self.opt_gui_layout.currentIndex()).toString()
- config['gui_layout'] = unicode(val)
- for x in ('gui', 'cs'):
- w = getattr(self, 'opt_%s_restriction'%x)
- self.db.prefs.set(x+'_restriction', unicode(w.currentText()))
-
- if must_restart:
- warning_dialog(self, _('Must restart'),
- _('The changes you made require that Calibre be '
- 'restarted. Please restart as soon as practical.'),
- show=True, show_copy_button=False)
- self.parent.must_restart_before_config = True
- QDialog.accept(self)
-
-class VacThread(QThread):
-
- def __init__(self, parent, db):
- QThread.__init__(self, parent)
- self.db = db
- self._parent = parent
-
- def run(self):
- err = bad = None
- try:
- bad = self.db.check_integrity(self.callback)
- except:
- import traceback
- err = traceback.format_exc()
- self.emit(SIGNAL('check_done(PyQt_PyObject, PyQt_PyObject)'), bad, err)
-
- def callback(self, progress, msg):
- self.emit(SIGNAL('callback(PyQt_PyObject,PyQt_PyObject)'), progress,
- msg)
-
-class CheckIntegrity(QProgressDialog):
-
- def __init__(self, db, parent=None):
- QProgressDialog.__init__(self, parent)
- self.db = db
- self.setCancelButton(None)
- self.setMinimum(0)
- self.setMaximum(100)
- self.setWindowTitle(_('Checking database integrity'))
- self.setAutoReset(False)
- self.setValue(0)
-
- self.vthread = VacThread(self, db)
- self.connect(self.vthread, SIGNAL('check_done(PyQt_PyObject,PyQt_PyObject)'),
- self.check_done,
- Qt.QueuedConnection)
- self.connect(self.vthread,
- SIGNAL('callback(PyQt_PyObject,PyQt_PyObject)'),
- self.callback, Qt.QueuedConnection)
- self.vthread.start()
-
- def callback(self, progress, msg):
- self.setLabelText(msg)
- self.setValue(int(100*progress))
-
- def check_done(self, bad, err):
- if err:
- error_dialog(self, _('Error'),
- _('Failed to check database integrity'),
- det_msg=err, show=True)
- elif bad:
- titles = [self.db.title(x, index_is_id=True) for x in bad]
- det_msg = '\n'.join(titles)
- warning_dialog(self, _('Some inconsistencies found'),
- _('The following books had formats listed in the '
- 'database that are not actually available. '
- 'The entries for the formats have been removed. '
- 'You should check them manually. This can '
- 'happen if you manipulate the files in the '
- 'library folder directly.'), det_msg=det_msg, show=True)
- self.reset()
-
-
-
-if __name__ == '__main__':
- from calibre.library.database2 import LibraryDatabase2
- from PyQt4.Qt import QApplication
- app = QApplication([])
- d=ConfigDialog(None, LibraryDatabase2('/tmp'))
- d.show()
- app.exec_()
diff --git a/src/calibre/gui2/dialogs/config/add_save.py b/src/calibre/gui2/dialogs/config/add_save.py
deleted file mode 100644
index 8eb6cf7bd0..0000000000
--- a/src/calibre/gui2/dialogs/config/add_save.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python
-# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import with_statement
-
-__license__ = 'GPL v3'
-__copyright__ = '2009, Kovid Goyal '
-__docformat__ = 'restructuredtext en'
-
-import textwrap
-
-from PyQt4.Qt import QTabWidget
-
-from calibre.gui2.dialogs.config.add_save_ui import Ui_TabWidget
-from calibre.library.save_to_disk import config
-from calibre.utils.config import prefs
-from calibre.gui2.widgets import FilenamePattern
-
-class AddSave(QTabWidget, Ui_TabWidget):
-
- def __init__(self, parent=None):
- QTabWidget.__init__(self, parent)
- self.setupUi(self)
- while self.count() > 3:
- self.removeTab(3)
- c = config()
- opts = c.parse()
- for x in ('asciiize', 'update_metadata', 'save_cover', 'write_opf',
- 'replace_whitespace', 'to_lowercase'):
- g = getattr(self, 'opt_'+x)
- g.setChecked(getattr(opts, x))
- help = '\n'.join(textwrap.wrap(c.get_option(x).help, 75))
- g.setToolTip(help)
- g.setWhatsThis(help)
-
- for x in ('formats', 'timefmt'):
- g = getattr(self, 'opt_'+x)
- g.setText(getattr(opts, x))
- help = '\n'.join(textwrap.wrap(c.get_option(x).help, 75))
- g.setToolTip(help)
- g.setWhatsThis(help)
-
-
- self.opt_read_metadata_from_filename.setChecked(not prefs['read_file_metadata'])
- self.filename_pattern = FilenamePattern(self)
- self.metadata_box.layout().insertWidget(0, self.filename_pattern)
- self.opt_swap_author_names.setChecked(prefs['swap_author_names'])
- self.opt_add_formats_to_existing.setChecked(prefs['add_formats_to_existing'])
- if prefs['manage_device_metadata'] == 'manual':
- self.manage_device_metadata.setCurrentIndex(0)
- elif prefs['manage_device_metadata'] == 'on_send':
- self.manage_device_metadata.setCurrentIndex(1)
- else:
- self.manage_device_metadata.setCurrentIndex(2)
- help = '\n'.join(textwrap.wrap(c.get_option('template').help, 75))
- self.save_template.initialize('save_to_disk', opts.template, help)
- self.send_template.initialize('send_to_device', opts.send_template, help)
-
- def validate(self):
- return self.save_template.validate() and self.send_template.validate()
-
- def save_settings(self):
- if not self.validate():
- return False
- c = config()
- for x in ('asciiize', 'update_metadata', 'save_cover', 'write_opf',
- 'replace_whitespace', 'to_lowercase'):
- c.set(x, getattr(self, 'opt_'+x).isChecked())
- for x in ('formats', 'timefmt'):
- val = unicode(getattr(self, 'opt_'+x).text()).strip()
- if x == 'formats' and not val:
- val = 'all'
- c.set(x, val)
- self.save_template.save_settings(c, 'template')
- self.send_template.save_settings(c, 'send_template')
- prefs['read_file_metadata'] = not bool(self.opt_read_metadata_from_filename.isChecked())
- pattern = self.filename_pattern.commit()
- prefs['filename_pattern'] = pattern
- prefs['swap_author_names'] = bool(self.opt_swap_author_names.isChecked())
- prefs['add_formats_to_existing'] = bool(self.opt_add_formats_to_existing.isChecked())
- if self.manage_device_metadata.currentIndex() == 0:
- prefs['manage_device_metadata'] = 'manual'
- elif self.manage_device_metadata.currentIndex() == 1:
- prefs['manage_device_metadata'] = 'on_send'
- else:
- prefs['manage_device_metadata'] = 'on_connect'
- return True
-
-if __name__ == '__main__':
- from PyQt4.Qt import QApplication
- app=QApplication([])
- a = AddSave()
- a.show()
- app.exec_()
- a.save_settings()
-
diff --git a/src/calibre/gui2/dialogs/config/add_save.ui b/src/calibre/gui2/dialogs/config/add_save.ui
deleted file mode 100644
index c8ee0419a9..0000000000
--- a/src/calibre/gui2/dialogs/config/add_save.ui
+++ /dev/null
@@ -1,280 +0,0 @@
-
-
- TabWidget
-
-
-
- 0
- 0
- 671
- 516
-
-
-
- TabWidget
-
-
- 0
-
-
-
- &Adding books
-
-
-
-
-
- Here you can control how calibre will read metadata from the files you add to it. calibre can either read metadata from the contents of the file, or from the filename.
-
-
- true
-
-
-
-
-
-
- Read metadata only from &file name
-
-
-
-
-
-
- Swap the firstname and lastname of the author. This affects only metadata read from file names.
-
-
- &Swap author firstname and lastname
-
-
-
-
-
-
- If an existing book with a similar title and author is found that does not have the format being added, the format is added
-to the existing book, instead of creating a new entry. If the existing book already has the format, then it is silently ignored.
-
-Title match ignores leading indefinite articles ("the", "a", "an"), punctuation, case, etc. Author match is exact.
-
-
- If books with similar titles and authors found, &merge the new files automatically
-
-
-
-
-
-
- &Configure metadata from file name
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 363
-
-
-
-
-
-
-
-
-
-
-
- &Saving books
-
-
-
-
-
- Here you can control how calibre will save your books when you click the Save to Disk button:
-
-
- true
-
-
-
-
-
-
- Save &cover separately
-
-
-
-
-
-
- Update &metadata in saved copies
-
-
-
-
-
-
- Save metadata in &OPF file
-
-
-
-
-
-
- Convert non-English characters to &English equivalents
-
-
-
-
-
-
- Format &dates as:
-
-
- opt_timefmt
-
-
-
-
-
-
-
-
-
- File &formats to save:
-
-
- opt_formats
-
-
-
-
-
-
-
-
-
- Replace space with &underscores
-
-
-
-
-
-
- Change paths to &lowercase
-
-
-
-
-
-
-
-
-
-
- Sending to &device
-
-
-
-
-
-
- 0
- 0
-
-
-
- Metadata &management:
-
-
- manage_device_metadata
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- Manual management
-
-
-
-
- Only on send
-
-
-
-
- Automatic management
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 313
- 20
-
-
-
-
-
-
-
- <li><b>Manual Management</b>: Calibre updates the metadata and adds collections only when a book is sent. With this option, calibre will never remove a collection.</li>
-<li><b>Only on send</b>: Calibre updates metadata and adds/removes collections for a book only when it is sent to the device. </li>
-<li><b>Automatic management</b>: Calibre automatically keeps metadata on the device in sync with the calibre library, on every connect</li></ul>
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
- Here you can control how calibre will save your books when you click the Send to Device button. This setting can be overriden for individual devices by customizing the device interface plugins in Preferences->Plugins
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
- SaveTemplate
- QWidget
- calibre/gui2/dialogs/config/save_template.h
- 1
-
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui
deleted file mode 100644
index 3dc30cbf36..0000000000
--- a/src/calibre/gui2/dialogs/config/config.ui
+++ /dev/null
@@ -1,1398 +0,0 @@
-
-
- Kovid Goyal
- Dialog
-
-
-
- 0
- 0
- 1001
- 730
-
-
-
- Preferences
-
-
-
- :/images/config.png:/images/config.png
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 75
- true
-
-
-
- QAbstractItemView::NoEditTriggers
-
-
- true
-
-
- false
-
-
-
- 48
- 48
-
-
-
- QAbstractItemView::ScrollPerItem
-
-
- QAbstractItemView::ScrollPerPixel
-
-
- QListView::TopToBottom
-
-
- 20
-
-
- QListView::ListMode
-
-
-
-
-
-
-
- 1
- 0
-
-
-
- QFrame::Plain
-
-
- 0
-
-
- true
-
-
-
-
- 0
- 0
- 725
- 683
-
-
-
-
- 0
-
-
-
-
-
- 100
- 0
-
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- Show notification when &new version is available
-
-
-
-
-
-
- Download &social metadata (tags/ratings/etc.) by default
-
-
-
-
-
-
- &Overwrite author and title by default when fetching metadata
-
-
-
-
-
-
-
-
- Default network &timeout:
-
-
- timeout
-
-
-
-
-
-
- Set the default timeout for network fetches (i.e. anytime we go out to the internet to get information)
-
-
- seconds
-
-
- 2
-
-
- 120
-
-
- 5
-
-
-
-
-
-
-
-
-
- Choose &language (requires restart):
-
-
- language
-
-
-
-
-
-
-
- Normal
-
-
-
-
- High
-
-
-
-
- Low
-
-
-
-
-
-
-
- Job &priority:
-
-
- priority
-
-
-
-
-
-
- Preferred &output format:
-
-
- output_format
-
-
-
-
-
-
-
-
-
- Tags to apply when adding a book:
-
-
- new_book_tags
-
-
-
-
-
-
- A comma-separated list of tags that will be applied to books added to the library
-
-
-
-
-
-
-
-
- Reset all disabled &confirmation dialogs
-
-
-
-
-
-
- Preferred &input format order:
-
-
-
-
-
-
-
- true
-
-
- QAbstractItemView::SelectRows
-
-
-
-
-
-
-
-
- ...
-
-
-
- :/images/arrow-up.png:/images/arrow-up.png
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- ...
-
-
-
- :/images/arrow-down.png:/images/arrow-down.png
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
- &Miscellaneous
-
-
-
-
-
- User Interface &layout (needs restart):
-
-
- opt_gui_layout
-
-
-
-
-
-
-
- 250
- 16777215
-
-
-
-
-
-
-
- &Number of covers to show in browse mode (needs restart):
-
-
- cover_browse
-
-
-
-
-
-
-
-
-
- Restriction to apply when the current library is opened:
-
-
- opt_gui_restriction
-
-
-
-
-
-
-
- 250
- 16777215
-
-
-
- Apply this restriction on calibre startup if the current library is being used. Also applied when switching to this library. Note that this setting is per library.
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
- 15
-
-
-
-
-
-
- Disable all animations. Useful if you have a slow/old computer.
-
-
- Disable &animations
-
-
-
-
-
-
- &Toolbar
-
-
-
-
-
-
-
-
- &Icon size:
-
-
- opt_toolbar_icon_size
-
-
-
-
-
-
-
-
-
- Show &text under icons:
-
-
- opt_toolbar_text
-
-
-
-
-
-
-
-
-
- &Delete news from library when it is automatically sent to reader
-
-
-
-
-
-
-
-
- Select visible &columns in library view
-
-
-
-
-
-
-
- true
-
-
- QAbstractItemView::SelectRows
-
-
-
-
-
-
-
-
- ...
-
-
-
- :/images/arrow-up.png:/images/arrow-up.png
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- Remove a user-defined column
-
-
- ...
-
-
-
- :/images/minus.png:/images/minus.png
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- Add a user-defined column
-
-
- ...
-
-
-
- :/images/plus.png:/images/plus.png
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- Edit settings of a user-defined column
-
-
- ...
-
-
-
- :/images/edit_input.png:/images/edit_input.png
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- ...
-
-
-
- :/images/arrow-down.png:/images/arrow-down.png
-
-
-
-
-
-
-
-
-
-
-
-
-
- Use internal &viewer for:
-
-
-
-
-
- true
-
-
- QAbstractItemView::NoSelection
-
-
-
-
-
-
-
-
-
-
-
- Search as you type
-
-
- true
-
-
-
-
-
-
- Use &Roman numerals for series
-
-
- true
-
-
-
-
-
-
- Enable system &tray icon (needs restart)
-
-
-
-
-
-
- Show &average ratings in the tags browser
-
-
- true
-
-
-
-
-
-
- Automatically send downloaded &news to ebook reader
-
-
-
-
-
-
- Show &splash screen at startup
-
-
-
-
-
-
- Show cover &browser in a separate window (needs restart)
-
-
-
-
-
-
- Show ¬ifications in system tray
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- QAbstractItemView::SingleSelection
-
-
- QAbstractItemView::SelectRows
-
-
-
-
-
-
-
-
- Add an email address to which to send books
-
-
- &Add email
-
-
-
- :/images/plus.png:/images/plus.png
-
-
-
- 24
- 24
-
-
-
- Qt::ToolButtonTextUnderIcon
-
-
-
-
-
-
- Make &default
-
-
-
-
-
-
- &Remove email
-
-
-
- :/images/minus.png:/images/minus.png
-
-
-
- 24
- 24
-
-
-
- Qt::ToolButtonTextUnderIcon
-
-
-
-
-
-
-
-
-
-
- calibre can send your books to you (or your reader) by email. Emails will be automatically sent for downloaded news to all email addresses that have Auto-send checked.
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
- &Miscellaneous
-
-
-
-
-
- &Maximum number of waiting worker processes (needs restart):
-
-
- opt_worker_limit
-
-
-
-
-
-
- 2
-
-
- 10000
-
-
- 2
-
-
-
-
-
-
- Limit the max. simultaneous jobs to the available CPU &cores
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 79
-
-
-
-
-
-
-
- Debug &device detection
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 80
-
-
-
-
-
-
-
- &Check database integrity
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 79
-
-
-
-
-
-
-
- Open calibre &configuration directory
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 80
-
-
-
-
-
-
-
- &Install command line tools
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 79
-
-
-
-
-
-
-
-
- &Tweaks
-
-
-
-
-
- Values for the tweaks are shown below. Edit them to change the behavior of calibre
-
-
- true
-
-
-
-
-
-
- All available tweaks
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
- &Current tweaks
-
-
-
-
-
-
-
-
-
-
-
- &Restore to defaults
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- calibre contains a network server that allows you to access your book collection using a browser from anywhere in the world. Any changes to the settings will only take effect after a server restart.
-
-
- true
-
-
-
-
-
-
-
-
- Server &port:
-
-
- port
-
-
-
-
-
-
- 65535
-
-
- 8080
-
-
-
-
-
-
- &Username:
-
-
- username
-
-
-
-
-
-
-
-
-
- &Password:
-
-
- password
-
-
-
-
-
-
- If you leave the password blank, anyone will be able to access your book collection using the web interface.
-
-
-
-
-
-
- The maximum size (widthxheight) for displayed covers. Larger covers are resized.
-
-
-
-
-
-
-
-
-
- Max. &cover size:
-
-
- max_cover_size
-
-
-
-
-
-
- &Show password
-
-
-
-
-
-
- Max. &OPDS items per query:
-
-
- opt_max_opds_items
-
-
-
-
-
-
- 10
-
-
- 10000
-
-
-
-
-
-
- 25
-
-
- 1000000
-
-
-
-
-
-
- Max. OPDS &ungrouped items:
-
-
- opt_max_opds_ungrouped_items
-
-
-
-
-
-
- Restriction (saved search) to apply:
-
-
-
-
-
-
- This restriction (based on a saved search) will restrict the books the content server makes available to those matching the search. This setting is per library (i.e. you can have a different restriction per library).
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
- 20
-
-
-
-
-
-
-
-
-
-
- &Start Server
-
-
-
-
-
-
- St&op Server
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
- &Test Server
-
-
-
-
-
-
-
-
- Run server &automatically on startup
-
-
-
-
-
-
- View &server logs
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- <p>Remember to leave calibre running as the server only runs as long as calibre is running.
-<p>Stanza should see your calibre collection automatically. If not, try adding the URL http://myhostname:8080 as a new catalog in the Stanza reader on your iPhone. Here myhostname should be the fully qualified hostname or the IP address of the computer calibre is running on.
-
-
- true
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
- Here you can customize the behavior of Calibre by controlling what plugins it uses.
-
-
- true
-
-
-
-
-
-
- true
-
-
-
- 32
- 32
-
-
-
- true
-
-
- true
-
-
- true
-
-
-
-
-
-
-
-
- Enable/&Disable plugin
-
-
-
-
-
-
- &Customize plugin
-
-
-
-
-
-
- &Remove plugin
-
-
-
-
-
-
-
-
- Add new plugin
-
-
-
-
-
-
-
- Plugin &file:
-
-
- plugin_path
-
-
-
-
-
-
-
-
-
- ...
-
-
-
- :/images/document_open.png:/images/document_open.png
-
-
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
- &Add
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
- SendEmail
- QWidget
- calibre/gui2/wizard/send_email.h
- 1
-
-
- AddSave
- QTabWidget
- calibre/gui2/dialogs/config/add_save.h
- 1
-
-
-
-
-
-
-
- buttonBox
- accepted()
- Dialog
- accept()
-
-
- 239
- 558
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- Dialog
- reject()
-
-
- 307
- 558
-
-
- 286
- 274
-
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/config/create_custom_column.py b/src/calibre/gui2/dialogs/config/create_custom_column.py
deleted file mode 100644
index c0f17b8cba..0000000000
--- a/src/calibre/gui2/dialogs/config/create_custom_column.py
+++ /dev/null
@@ -1,173 +0,0 @@
-__license__ = 'GPL v3'
-__copyright__ = '2010, Kovid Goyal '
-
-'''Dialog to create a new custom column'''
-
-import re
-from functools import partial
-
-from PyQt4.QtCore import SIGNAL
-from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant
-
-from calibre.gui2.dialogs.config.create_custom_column_ui import Ui_QCreateCustomColumn
-from calibre.gui2 import error_dialog
-
-class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
-
- column_types = {
- 0:{'datatype':'text',
- 'text':_('Text, column shown in the tag browser'),
- 'is_multiple':False},
- 1:{'datatype':'*text',
- 'text':_('Comma separated text, like tags, shown in the tag browser'),
- 'is_multiple':True},
- 2:{'datatype':'comments',
- 'text':_('Long text, like comments, not shown in the tag browser'),
- 'is_multiple':False},
- 3:{'datatype':'series',
- 'text':_('Text column for keeping series-like information'),
- 'is_multiple':False},
- 4:{'datatype':'datetime',
- 'text':_('Date'), 'is_multiple':False},
- 5:{'datatype':'float',
- 'text':_('Floating point numbers'), 'is_multiple':False},
- 6:{'datatype':'int',
- 'text':_('Integers'), 'is_multiple':False},
- 7:{'datatype':'rating',
- 'text':_('Ratings, shown with stars'),
- 'is_multiple':False},
- 8:{'datatype':'bool',
- 'text':_('Yes/No'), 'is_multiple':False},
- }
-
- def __init__(self, parent, editing, standard_colheads, standard_colnames):
- QDialog.__init__(self, parent)
- Ui_QCreateCustomColumn.__init__(self)
- self.setupUi(self)
- # Remove help icon on title bar
- icon = self.windowIcon()
- self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint))
- self.setWindowIcon(icon)
-
- self.simple_error = partial(error_dialog, self, show=True,
- show_copy_button=False)
- self.connect(self.button_box, SIGNAL("accepted()"), self.accept)
- self.connect(self.button_box, SIGNAL("rejected()"), self.reject)
- self.parent = parent
- self.editing_col = editing
- self.standard_colheads = standard_colheads
- self.standard_colnames = standard_colnames
- for t in self.column_types:
- self.column_type_box.addItem(self.column_types[t]['text'])
- self.column_type_box.currentIndexChanged.connect(self.datatype_changed)
- if not self.editing_col:
- self.datatype_changed()
- self.exec_()
- return
- idx = parent.columns.currentRow()
- if idx < 0:
- self.simple_error(_('No column selected'),
- _('No column has been selected'))
- return
- col = unicode(parent.columns.item(idx).data(Qt.UserRole).toString())
- if col not in parent.custcols:
- self.simple_error('', _('Selected column is not a user-defined column'))
- return
-
- c = parent.custcols[col]
- self.column_name_box.setText(c['label'])
- self.column_heading_box.setText(c['name'])
- ct = c['datatype'] if not c['is_multiple'] else '*text'
- self.orig_column_number = c['colnum']
- self.orig_column_name = col
- column_numbers = dict(map(lambda x:(self.column_types[x]['datatype'], x), self.column_types))
- self.column_type_box.setCurrentIndex(column_numbers[ct])
- self.column_type_box.setEnabled(False)
- if ct == 'datetime':
- if c['display'].get('date_format', None):
- self.date_format_box.setText(c['display'].get('date_format', ''))
- self.datatype_changed()
- self.exec_()
-
- def datatype_changed(self, *args):
- try:
- col_type = self.column_types[self.column_type_box.currentIndex()]['datatype']
- except:
- col_type = None
- df_visible = col_type == 'datetime'
- for x in ('box', 'default_label', 'label'):
- getattr(self, 'date_format_'+x).setVisible(df_visible)
-
-
- def accept(self):
- col = unicode(self.column_name_box.text())
- if not col:
- return self.simple_error('', _('No lookup name was provided'))
- if re.match('^\w*$', col) is None or not col[0].isalpha() or col.lower() != col:
- return self.simple_error('', _('The lookup name must contain only lower case letters, digits and underscores, and start with a letter'))
- if col.endswith('_index'):
- return self.simple_error('', _('Lookup names cannot end with _index, because these names are reserved for the index of a series column.'))
- col_heading = unicode(self.column_heading_box.text())
- col_type = self.column_types[self.column_type_box.currentIndex()]['datatype']
- if col_type == '*text':
- col_type='text'
- is_multiple = True
- else:
- is_multiple = False
- if not col_heading:
- return self.simple_error('', _('No column heading was provided'))
- bad_col = False
- if col in self.parent.custcols:
- if not self.editing_col or self.parent.custcols[col]['colnum'] != self.orig_column_number:
- bad_col = True
- if bad_col:
- return self.simple_error('', _('The lookup name %s is already used')%col)
- bad_head = False
- for t in self.parent.custcols:
- if self.parent.custcols[t]['name'] == col_heading:
- if not self.editing_col or self.parent.custcols[t]['colnum'] != self.orig_column_number:
- bad_head = True
- for t in self.standard_colheads:
- if self.standard_colheads[t] == col_heading:
- bad_head = True
- if bad_head:
- return self.simple_error('', _('The heading %s is already used')%col_heading)
-
- date_format = {}
- if col_type == 'datetime':
- if self.date_format_box.text():
- date_format = {'date_format':unicode(self.date_format_box.text())}
- else:
- date_format = {'date_format': None}
-
- key = self.parent.db.field_metadata.custom_field_prefix+col
- if not self.editing_col:
- self.parent.db.field_metadata
- self.parent.custcols[key] = {
- 'label':col,
- 'name':col_heading,
- 'datatype':col_type,
- 'editable':True,
- 'display':date_format,
- 'normalized':None,
- 'colnum':None,
- 'is_multiple':is_multiple,
- }
- item = QListWidgetItem(col_heading, self.parent.columns)
- item.setData(Qt.UserRole, QVariant(key))
- item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable|Qt.ItemIsSelectable)
- item.setCheckState(Qt.Checked)
- else:
- idx = self.parent.columns.currentRow()
- item = self.parent.columns.item(idx)
- item.setData(Qt.UserRole, QVariant(key))
- item.setText(col_heading)
- self.parent.custcols[self.orig_column_name]['label'] = col
- self.parent.custcols[self.orig_column_name]['name'] = col_heading
- self.parent.custcols[self.orig_column_name]['display'].update(date_format)
- self.parent.custcols[self.orig_column_name]['*edited'] = True
- self.parent.custcols[self.orig_column_name]['*must_restart'] = True
- QDialog.accept(self)
-
- def reject(self):
- QDialog.reject(self)
diff --git a/src/calibre/gui2/dialogs/config/create_custom_column.ui b/src/calibre/gui2/dialogs/config/create_custom_column.ui
deleted file mode 100644
index 5cb9494845..0000000000
--- a/src/calibre/gui2/dialogs/config/create_custom_column.ui
+++ /dev/null
@@ -1,191 +0,0 @@
-
-
- QCreateCustomColumn
-
-
- Qt::ApplicationModal
-
-
-
- 0
- 0
- 528
- 199
-
-
-
-
- 0
- 0
-
-
-
- Create or edit custom columns
-
-
-
-
-
- QLayout::SetDefaultConstraint
-
-
- 5
-
-
-
-
- 0
-
-
-
-
- &Lookup name
-
-
- column_name_box
-
-
-
-
-
-
- Column &heading
-
-
- column_heading_box
-
-
-
-
-
-
-
- 20
- 0
-
-
-
- Used for searching the column. Must contain only digits and lower case letters.
-
-
-
-
-
-
- Column heading in the library view and category name in the tag browser
-
-
-
-
-
-
- Column &type
-
-
- column_type_box
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 70
- 0
-
-
-
- What kind of information will be kept in the column.
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- <p>Date format. Use 1-4 'd's for day, 1-4 'M's for month, and 2 or 4 'y's for year.</p>
-<p>For example:
-<ul>
-<li> ddd, d MMM yyyy gives Mon, 5 Jan 2010<li>
-<li>dd MMMM yy gives 05 January 10</li>
-</ul>
-
-
-
-
-
-
- Use MMM yyyy for month + year, yyyy for year only
-
-
- Default: dd MMM yyyy.
-
-
-
-
-
-
-
-
- Format for &dates
-
-
- date_format_box
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
- true
-
-
-
-
-
-
-
- 75
- true
-
-
-
- Create or edit custom columns
-
-
-
-
-
-
-
-
- column_name_box
- column_heading_box
- column_type_box
- date_format_box
- button_box
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/config/history.py b/src/calibre/gui2/dialogs/config/history.py
deleted file mode 100644
index 74b88a4380..0000000000
--- a/src/calibre/gui2/dialogs/config/history.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import with_statement
-
-__license__ = 'GPL v3'
-__copyright__ = '2009, Kovid Goyal '
-__docformat__ = 'restructuredtext en'
-
-from PyQt4.Qt import QComboBox, QStringList, Qt
-
-from calibre.gui2 import config as gui_conf
-
-class HistoryBox(QComboBox):
-
- def __init__(self, parent=None):
- QComboBox.__init__(self, parent)
- self.setEditable(True)
-
- def initialize(self, opt_name, default, help=None):
- history = gui_conf[opt_name]
- if default not in history:
- history.append(default)
- self.addItems(QStringList(history))
- self.setCurrentIndex(self.findText(default, Qt.MatchFixedString))
- if help is not None:
- self.setToolTip(help)
- self.setWhatsThis(help)
-
- def save_history(self, opt_name):
- history = [unicode(self.itemText(i)) for i in range(self.count())]
- ct = self.text()
- if ct not in history:
- history = [ct] + history
- gui_conf[opt_name] = history[:10]
-
- def text(self):
- return unicode(self.currentText()).strip()
-
-
-
diff --git a/src/calibre/gui2/dialogs/config/save_template.py b/src/calibre/gui2/dialogs/config/save_template.py
deleted file mode 100644
index 71eb15f4aa..0000000000
--- a/src/calibre/gui2/dialogs/config/save_template.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import with_statement
-
-__license__ = 'GPL v3'
-__copyright__ = '2009, Kovid Goyal '
-__docformat__ = 'restructuredtext en'
-
-from PyQt4.Qt import QWidget
-
-from calibre.gui2 import error_dialog
-from calibre.gui2.dialogs.config.save_template_ui import Ui_Form
-from calibre.library.save_to_disk import FORMAT_ARG_DESCS, \
- preprocess_template
-
-class SaveTemplate(QWidget, Ui_Form):
-
- def __init__(self, *args):
- QWidget.__init__(self, *args)
- Ui_Form.__init__(self)
- self.setupUi(self)
-
- def initialize(self, name, default, help):
- variables = sorted(FORMAT_ARG_DESCS.keys())
- rows = []
- for var in variables:
- rows.append(u'
%s
%s
'%
- (var, FORMAT_ARG_DESCS[var]))
- table = u'
%s
'%(u'\n'.join(rows))
- self.template_variables.setText(table)
-
- self.opt_template.initialize(name+'_template_history',
- default, help)
- self.option_name = name
-
- def validate(self):
- tmpl = preprocess_template(self.opt_template.text())
- fa = {}
- for x in FORMAT_ARG_DESCS.keys():
- fa[x]='random long string'
- try:
- tmpl.format(**fa)
- except Exception, err:
- error_dialog(self, _('Invalid template'),
- '
'+_('The template %s is invalid:')%tmpl + \
- ' '+str(err), show=True)
- return False
- return True
-
- def save_settings(self, config, name):
- val = unicode(self.opt_template.text())
- config.set(name, val)
- self.opt_template.save_history(self.option_name+'_template_history')
-
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/config/save_template.ui b/src/calibre/gui2/dialogs/config/save_template.ui
deleted file mode 100644
index 02506891bb..0000000000
--- a/src/calibre/gui2/dialogs/config/save_template.ui
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 400
- 300
-
-
-
- Form
-
-
-
-
-
- Save &template
-
-
-
-
-
- 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.
-
-
- true
-
-
-
-
-
-
- Available variables:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- HistoryBox
- QComboBox
- calibre/gui2/dialogs/config/history.h
-
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/config/toolbar.py b/src/calibre/gui2/dialogs/config/toolbar.py
deleted file mode 100644
index 62e249d073..0000000000
--- a/src/calibre/gui2/dialogs/config/toolbar.py
+++ /dev/null
@@ -1,295 +0,0 @@
-#!/usr/bin/env python
-# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-
-__license__ = 'GPL v3'
-__copyright__ = '2010, Kovid Goyal '
-__docformat__ = 'restructuredtext en'
-
-from functools import partial
-
-from PyQt4.Qt import QWidget, QAbstractListModel, Qt, QIcon, \
- QVariant, QItemSelectionModel
-
-from calibre.gui2.dialogs.config.toolbar_ui import Ui_Form
-from calibre.gui2 import gprefs, NONE, warning_dialog
-
-
-class FakeAction(object):
-
- def __init__(self, name, icon, tooltip=None,
- dont_add_to=frozenset([]), dont_remove_from=frozenset([])):
- self.name = name
- self.action_spec = (name, icon, tooltip, None)
- self.dont_remove_from = dont_remove_from
- self.dont_add_to = dont_add_to
-
-class BaseModel(QAbstractListModel):
-
- def name_to_action(self, name, gui):
- if name == 'Donate':
- return FakeAction(name, 'donate.png',
- dont_add_to=frozenset(['context-menu',
- 'context-menu-device']))
- if name == 'Location Manager':
- return FakeAction(name, None,
- _('Switch between library and device views'),
- dont_remove_from=set(['toolbar-device']))
- if name is None:
- return FakeAction('--- '+_('Separator')+' ---', None)
- return gui.iactions[name]
-
- def rowCount(self, parent):
- return len(self._data)
-
- def data(self, index, role):
- row = index.row()
- action = self._data[row].action_spec
- if role == Qt.DisplayRole:
- text = action[0]
- text = text.replace('&', '')
- if text == _('%d books'):
- text = _('Choose library')
- return QVariant(text)
- if role == Qt.DecorationRole:
- ic = action[1]
- if ic is None:
- ic = 'blank.png'
- return QVariant(QIcon(I(ic)))
- if role == Qt.ToolTipRole and action[2] is not None:
- return QVariant(action[2])
- return NONE
-
- def names(self, indexes):
- rows = [i.row() for i in indexes]
- ans = []
- for i in rows:
- n = self._data[i].name
- if n.startswith('---'):
- n = None
- ans.append(n)
- return ans
-
-
-class AllModel(BaseModel):
-
- def __init__(self, key, gui):
- BaseModel.__init__(self)
- self.gprefs_name = 'action-layout-'+key
- current = gprefs[self.gprefs_name]
- self.gui = gui
- self.key = key
- self._data = self.get_all_actions(current)
-
- def get_all_actions(self, current):
- all = list(self.gui.iactions.keys()) + ['Donate']
- all = [x for x in all if x not in current] + [None]
- all = [self.name_to_action(x, self.gui) for x in all]
- all = [x for x in all if self.key not in x.dont_add_to]
- all.sort()
- return all
-
- def add(self, names):
- actions = []
- for name in names:
- if name is None or name.startswith('---'): continue
- actions.append(self.name_to_action(name, self.gui))
- self._data.extend(actions)
- self._data.sort()
- self.reset()
-
- def remove(self, indices, allowed):
- rows = [i.row() for i in indices]
- remove = set([])
- for row in rows:
- ac = self._data[row]
- if ac.name.startswith('---'): continue
- if ac.name in allowed:
- remove.add(row)
- ndata = []
- for i, ac in enumerate(self._data):
- if i not in remove:
- ndata.append(ac)
- self._data = ndata
- self.reset()
-
- def restore_defaults(self):
- current = gprefs.defaults[self.gprefs_name]
- self._data = self.get_all_actions(current)
- self.reset()
-
-class CurrentModel(BaseModel):
-
- def __init__(self, key, gui):
- BaseModel.__init__(self)
- self.gprefs_name = 'action-layout-'+key
- current = gprefs[self.gprefs_name]
- self._data = [self.name_to_action(x, gui) for x in current]
- self.key = key
- self.gui = gui
-
- def move(self, idx, delta):
- row = idx.row()
- if row < 0 or row >= len(self._data):
- return
- nrow = row + delta
- if nrow < 0 or nrow >= len(self._data):
- return
- t = self._data[row]
- self._data[row] = self._data[nrow]
- self._data[nrow] = t
- ni = self.index(nrow)
- self.dataChanged.emit(idx, idx)
- self.dataChanged.emit(ni, ni)
- return ni
-
- def add(self, names):
- actions = []
- reject = set([])
- for name in names:
- ac = self.name_to_action(name, self.gui)
- if self.key in ac.dont_add_to:
- reject.add(ac)
- else:
- actions.append(ac)
-
- self._data.extend(actions)
- self.reset()
- return reject
-
- def remove(self, indices):
- rows = [i.row() for i in indices]
- remove, rejected = set([]), set([])
- for row in rows:
- ac = self._data[row]
- if self.key in ac.dont_remove_from:
- rejected.add(ac)
- continue
- remove.add(row)
- ndata = []
- for i, ac in enumerate(self._data):
- if i not in remove:
- ndata.append(ac)
- self._data = ndata
- self.reset()
- return rejected
-
- def commit(self):
- old = gprefs[self.gprefs_name]
- new = []
- for x in self._data:
- n = x.name
- if n.startswith('---'):
- n = None
- new.append(n)
- new = tuple(new)
- if new != old:
- defaults = gprefs.defaults[self.gprefs_name]
- if defaults == new:
- del gprefs[self.gprefs_name]
- else:
- gprefs[self.gprefs_name] = new
-
- def restore_defaults(self):
- current = gprefs.defaults[self.gprefs_name]
- self._data = [self.name_to_action(x, self.gui) for x in current]
- self.reset()
-
-
-class ToolbarLayout(QWidget, Ui_Form):
-
- LOCATIONS = [
- ('toolbar', _('The main toolbar')),
- ('toolbar-device', _('The main toolbar when a device is connected')),
- ('context-menu', _('The context menu for the books in the '
- 'calibre library')),
- ('context-menu-device', _('The context menu for the books on '
- 'the device'))
- ]
-
- def __init__(self, gui, parent=None):
- QWidget.__init__(self, parent)
- self.setupUi(self)
-
- self.models = {}
- for key, text in self.LOCATIONS:
- self.what.addItem(text, key)
- all_model = AllModel(key, gui)
- current_model = CurrentModel(key, gui)
- self.models[key] = (all_model, current_model)
- self.what.setCurrentIndex(0)
- self.what.currentIndexChanged[int].connect(self.what_changed)
- self.what_changed(0)
-
- self.add_action_button.clicked.connect(self.add_action)
- self.remove_action_button.clicked.connect(self.remove_action)
- self.restore_defaults_button.clicked.connect(self.restore_defaults)
- self.action_up_button.clicked.connect(partial(self.move, -1))
- self.action_down_button.clicked.connect(partial(self.move, 1))
-
- def what_changed(self, idx):
- key = unicode(self.what.itemData(idx).toString())
- self.all_actions.setModel(self.models[key][0])
- self.current_actions.setModel(self.models[key][1])
-
- def add_action(self, *args):
- x = self.all_actions.selectionModel().selectedIndexes()
- names = self.all_actions.model().names(x)
- if names:
- not_added = self.current_actions.model().add(names)
- ns = set([x.name for x in not_added])
- added = set(names) - ns
- self.all_actions.model().remove(x, added)
- if not_added:
- warning_dialog(self, _('Cannot add'),
- _('Cannot add the actions %s to this location') %
- ','.join([a.action_spec[0] for a in not_added]),
- show=True)
- if added:
- ca = self.current_actions
- idx = ca.model().index(ca.model().rowCount(None)-1)
- ca.scrollTo(idx)
-
- def remove_action(self, *args):
- x = self.current_actions.selectionModel().selectedIndexes()
- names = self.current_actions.model().names(x)
- if names:
- not_removed = self.current_actions.model().remove(x)
- ns = set([x.name for x in not_removed])
- removed = set(names) - ns
- self.all_actions.model().add(removed)
- if not_removed:
- warning_dialog(self, _('Cannot remove'),
- _('Cannot remove the actions %s from this location') %
- ','.join([a.action_spec[0] for a in not_removed]),
- show=True)
-
- def move(self, delta, *args):
- ci = self.current_actions.currentIndex()
- m = self.current_actions.model()
- if ci.isValid():
- ni = m.move(ci, delta)
- if ni is not None:
- self.current_actions.setCurrentIndex(ni)
- self.current_actions.selectionModel().select(ni,
- QItemSelectionModel.ClearAndSelect)
-
- def commit(self):
- for am, cm in self.models.values():
- cm.commit()
-
- def restore_defaults(self, *args):
- for am, cm in self.models.values():
- cm.restore_defaults()
- am.restore_defaults()
-
-
-if __name__ == '__main__':
- from PyQt4.Qt import QApplication
- from calibre.gui2.ui import Main
- app=QApplication([])
- m = Main(None)
- a = ToolbarLayout(m)
- a.show()
- app.exec_()
- a.commit()
-
diff --git a/src/calibre/gui2/dialogs/config/toolbar.ui b/src/calibre/gui2/dialogs/config/toolbar.ui
deleted file mode 100644
index 7ae98371ff..0000000000
--- a/src/calibre/gui2/dialogs/config/toolbar.ui
+++ /dev/null
@@ -1,223 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 831
- 553
-
-
-
- Form
-
-
-
-
-
- Customize the actions in:
-
-
-
-
-
-
- QComboBox::AdjustToMinimumContentsLengthWithIcon
-
-
- 20
-
-
-
-
-
-
- A&vailable actions
-
-
-
-
-
- QAbstractItemView::MultiSelection
-
-
-
- 32
- 32
-
-
-
- 10
-
-
- true
-
-
-
-
-
-
-
-
-
- &Current actions
-
-
-
-
-
- QAbstractItemView::MultiSelection
-
-
-
- 32
- 32
-
-
-
- 10
-
-
- true
-
-
-
-
-
-
-
-
- Move selected action up
-
-
- ...
-
-
-
- :/images/arrow-up.png:/images/arrow-up.png
-
-
-
- 24
- 24
-
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- Move selected action down
-
-
- ...
-
-
-
- :/images/arrow-down.png:/images/arrow-down.png
-
-
-
- 24
- 24
-
-
-
- Ctrl+S
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add selected actions to toolbar
-
-
- ...
-
-
-
- :/images/forward.png:/images/forward.png
-
-
-
- 24
- 24
-
-
-
-
-
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- Remove selected actions from toolbar
-
-
- ...
-
-
-
- :/images/back.png:/images/back.png
-
-
-
- 24
- 24
-
-
-
-
-
-
-
-
-
- Restore to &default
-
-
-
-
-
-
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index 860785c49e..1393a50738 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -30,7 +30,7 @@ from calibre.ebooks.metadata import MetaInformation
from calibre.utils.config import prefs, tweaks
from calibre.utils.date import qt_to_dt, local_tz, utcfromtimestamp
from calibre.customize.ui import run_plugins_on_import, get_isbndb_key
-from calibre.gui2.dialogs.config.social import SocialMetadata
+from calibre.gui2.preferences.social import SocialMetadata
from calibre.gui2.custom_column_widgets import populate_metadata_page
from calibre import strftime
diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui
index 4ea68f539d..7184192eba 100644
--- a/src/calibre/gui2/dialogs/metadata_single.ui
+++ b/src/calibre/gui2/dialogs/metadata_single.ui
@@ -646,7 +646,7 @@
- Download &cover
+ Download co&ver
diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py
index 51b17426b8..74f511e6a2 100644
--- a/src/calibre/gui2/init.py
+++ b/src/calibre/gui2/init.py
@@ -258,7 +258,9 @@ class LayoutMixin(object): # {{{
getattr(self, x+'_view').save_state()
for x in ('cb', 'tb', 'bd'):
- getattr(self, x+'_splitter').save_state()
+ s = getattr(self, x+'_splitter')
+ s.update_desired_state()
+ s.save_state()
def read_layout_settings(self):
# View states are restored automatically when set_database is called
diff --git a/src/calibre/gui2/preferences/__init__.py b/src/calibre/gui2/preferences/__init__.py
index cc5fa4fa8c..045d7ceebb 100644
--- a/src/calibre/gui2/preferences/__init__.py
+++ b/src/calibre/gui2/preferences/__init__.py
@@ -20,6 +20,8 @@ class ConfigWidgetInterface(object):
changed_signal = None
supports_restoring_to_defaults = True
+ restore_defaults_desc = _('Restore settings to default values. '
+ 'You have to click Apply to actually save the default settings.')
def genesis(self, gui):
raise NotImplementedError()
@@ -39,6 +41,9 @@ class ConfigWidgetInterface(object):
'''
return False
+ def refresh_gui(self, gui):
+ pass
+
class Setting(object):
def __init__(self, name, config_obj, widget, gui_name=None,
diff --git a/src/calibre/gui2/preferences/conversion.py b/src/calibre/gui2/preferences/conversion.py
index 82d6f916b8..0063d4a341 100644
--- a/src/calibre/gui2/preferences/conversion.py
+++ b/src/calibre/gui2/preferences/conversion.py
@@ -34,6 +34,10 @@ class Model(QStringListModel):
class Base(ConfigWidgetBase, Ui_Form):
+ restore_defaults_desc = _('Restore settings to default values. '
+ 'Only settings for the currently selected section '
+ 'are restored.')
+
def genesis(self, gui):
log = Log()
log.outputs = []
diff --git a/src/calibre/gui2/dialogs/config/device_debug.py b/src/calibre/gui2/preferences/device_debug.py
similarity index 100%
rename from src/calibre/gui2/dialogs/config/device_debug.py
rename to src/calibre/gui2/preferences/device_debug.py
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index a0805e8915..f30b2fddbb 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -23,7 +23,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('gui_layout', config, restart_required=True, choices=
[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')])
- r('cover_flow_queue_length', config)
+ r('cover_flow_queue_length', config, restart_required=True)
lang = get_lang()
if lang is None or lang not in available_translations():
@@ -55,6 +55,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
(_('Never'), 'never')]
r('toolbar_text', gprefs, choices=choices)
+ def refresh_gui(self, gui):
+ gui.search.search_as_you_type(config['search_as_you_type'])
+
+
if __name__ == '__main__':
from PyQt4.Qt import QApplication
app = QApplication([])
diff --git a/src/calibre/gui2/preferences/main.py b/src/calibre/gui2/preferences/main.py
new file mode 100644
index 0000000000..6524faec2d
--- /dev/null
+++ b/src/calibre/gui2/preferences/main.py
@@ -0,0 +1,305 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+
+__license__ = 'GPL v3'
+__copyright__ = '2010, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+import textwrap
+from functools import partial
+
+from PyQt4.Qt import QMainWindow, Qt, QIcon, QStatusBar, QFont, QWidget, \
+ QScrollArea, QStackedWidget, QVBoxLayout, QLabel, QFrame, QKeySequence, \
+ QToolBar, QSize, pyqtSignal, QSizePolicy, QToolButton, QAction, \
+ QPushButton, QHBoxLayout
+
+from calibre.constants import __appname__, __version__, islinux, isosx
+from calibre.gui2 import gprefs, min_available_height, available_width, \
+ warning_dialog
+from calibre.gui2.preferences import init_gui, AbortCommit, get_plugin
+from calibre.customize.ui import preferences_plugins
+from calibre.utils.ordered_dict import OrderedDict
+
+class StatusBar(QStatusBar): # {{{
+
+ def __init__(self, parent=None):
+ QStatusBar.__init__(self, parent)
+ self.default_message = __appname__ + ' ' + _('version') + ' ' + \
+ __version__ + ' ' + _('created by Kovid Goyal')
+ self.device_string = ''
+ self._font = QFont()
+ self._font.setBold(True)
+ self.setFont(self._font)
+
+ self.messageChanged.connect(self.message_changed,
+ type=Qt.QueuedConnection)
+ self.message_changed('')
+
+ def message_changed(self, msg):
+ if not msg or msg.isEmpty() or msg.isNull() or \
+ not unicode(msg).strip():
+ self.showMessage(self.default_message)
+
+# }}}
+
+class Category(QWidget): # {{{
+
+ plugin_activated = pyqtSignal(object)
+
+ def __init__(self, name, plugins, parent=None):
+ QWidget.__init__(self, parent)
+ self._layout = QVBoxLayout()
+ self.setLayout(self._layout)
+ self.label = QLabel(name)
+ self.sep = QFrame(self)
+ self.bf = QFont()
+ self.bf.setBold(True)
+ self.label.setFont(self.bf)
+ self.sep.setFrameShape(QFrame.HLine)
+ self._layout.addWidget(self.label)
+ self._layout.addWidget(self.sep)
+
+ self.plugins = plugins
+
+ self.bar = QToolBar(self)
+ self.bar.setIconSize(QSize(48, 48))
+ self.bar.setMovable(False)
+ self.bar.setFloatable(False)
+ self.bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
+ self._layout.addWidget(self.bar)
+ self.actions = []
+ for p in plugins:
+ target = partial(self.triggered, p)
+ ac = self.bar.addAction(QIcon(p.icon), p.gui_name, target)
+ ac.setToolTip(textwrap.fill(p.description))
+ ac.setWhatsThis(textwrap.fill(p.description))
+ ac.setStatusTip(p.description)
+ self.actions.append(ac)
+ w = self.bar.widgetForAction(ac)
+ w.setStyleSheet('QToolButton { margin-right: 20px; min-width: 100px }')
+ w.setCursor(Qt.PointingHandCursor)
+ w.setAutoRaise(True)
+
+ def triggered(self, plugin, *args):
+ self.plugin_activated.emit(plugin)
+
+# }}}
+
+class Browser(QScrollArea): # {{{
+
+ show_plugin = pyqtSignal(object)
+ close_signal = pyqtSignal()
+
+ def __init__(self, parent=None):
+ QScrollArea.__init__(self, parent)
+ self.setWidgetResizable(True)
+
+ category_map = {}
+ for plugin in preferences_plugins():
+ if plugin.category not in category_map:
+ category_map[plugin.category] = plugin.category_order
+ if category_map[plugin.category] < plugin.category_order:
+ category_map[plugin.category] = plugin.category_order
+
+ categories = list(category_map.keys())
+ categories.sort(cmp=lambda x, y: cmp(category_map[x], category_map[y]))
+
+ self.category_map = OrderedDict()
+ for c in categories:
+ self.category_map[c] = []
+
+ for plugin in preferences_plugins():
+ self.category_map[plugin.category].append(plugin)
+
+ for plugins in self.category_map.values():
+ plugins.sort(cmp=lambda x, y: cmp(x.name_order, y.name_order))
+
+ self.widgets = []
+ self._layout = QVBoxLayout()
+ self.container = QWidget(self)
+ self.container.setLayout(self._layout)
+ self.setWidget(self.container)
+ if isosx:
+ self._osxl = QHBoxLayout()
+ self.close_button = QPushButton(_('Close'))
+ self.close_button.clicked.connect(self.close_requested)
+ self._osxl.addStretch(10)
+ self._osxl.addWidget(self.close_button)
+ #self._osxl.addStretch(10)
+ self._layout.addLayout(self._osxl)
+
+ for name, plugins in self.category_map.items():
+ w = Category(name, plugins, self)
+ self.widgets.append(w)
+ self._layout.addWidget(w)
+ w.plugin_activated.connect(self.show_plugin.emit)
+
+ def close_requested(self, *args):
+ self.close_signal.emit()
+
+# }}}
+
+class Preferences(QMainWindow):
+
+ def __init__(self, gui, initial_plugin=None):
+ QMainWindow.__init__(self, gui)
+ self.gui = gui
+ self.must_restart = False
+ self.committed = False
+
+ self.resize(900, 760 if isosx else 710)
+ nh, nw = min_available_height()-25, available_width()-10
+ if nh < 0:
+ nh = 800
+ if nw < 0:
+ nw = 600
+ nh = min(self.height(), nh)
+ nw = min(self.width(), nw)
+ self.resize(nw, nh)
+ self.esc_action = QAction(self)
+ self.addAction(self.esc_action)
+ self.esc_action.setShortcut(QKeySequence(Qt.Key_Escape))
+ self.esc_action.triggered.connect(self.esc)
+
+ geom = gprefs.get('preferences_window_geometry', None)
+ if geom is not None:
+ self.restoreGeometry(geom)
+
+ # Center
+ if islinux:
+ self.move(gui.rect().center() - self.rect().center())
+
+ self.setWindowModality(Qt.WindowModal)
+ self.setWindowTitle(__appname__ + ' - ' + _('Preferences'))
+ self.setWindowIcon(QIcon(I('config.png')))
+
+ self.status_bar = StatusBar(self)
+ self.setStatusBar(self.status_bar)
+
+ self.stack = QStackedWidget(self)
+ self.setCentralWidget(self.stack)
+ self.browser = Browser(self)
+ self.browser.close_signal.connect(self.close, type=Qt.QueuedConnection)
+ self.browser.show_plugin.connect(self.show_plugin)
+ self.stack.addWidget(self.browser)
+ self.scroll_area = QScrollArea(self)
+ self.stack.addWidget(self.scroll_area)
+ self.scroll_area.setWidgetResizable(True)
+
+ self.bar = QToolBar(self)
+ self.addToolBar(self.bar)
+ self.bar.setVisible(False)
+ self.bar.setIconSize(QSize(32, 32))
+ self.bar.setMovable(False)
+ self.bar.setFloatable(False)
+ self.bar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
+ self.apply_action = self.bar.addAction(QIcon(I('ok.png')), _('&Apply'),
+ self.commit)
+ self.cancel_action = self.bar.addAction(QIcon(I('window-close.png')),
+ _('&Cancel'), self.cancel)
+ self.bar_filler = QLabel('')
+ self.bar_filler.setSizePolicy(QSizePolicy.Expanding,
+ QSizePolicy.Preferred)
+ self.bar_filler.setStyleSheet(
+ 'QLabel { font-weight: bold }')
+ self.bar_filler.setAlignment(Qt.AlignHCenter | Qt.AlignCenter)
+ self.bar.addWidget(self.bar_filler)
+ self.restore_action = self.bar.addAction(QIcon(I('clear_left.png')),
+ _('Restore &defaults'), self.restore_defaults)
+ for ac, tt in [('apply', _('Save changes')),
+ ('cancel', _('Cancel and return to overview'))]:
+ ac = getattr(self, ac+'_action')
+ ac.setToolTip(tt)
+ ac.setWhatsThis(tt)
+ ac.setStatusTip(tt)
+
+ for ch in self.bar.children():
+ if isinstance(ch, QToolButton):
+ ch.setCursor(Qt.PointingHandCursor)
+ ch.setAutoRaise(True)
+
+ self.stack.setCurrentIndex(0)
+
+ if initial_plugin is not None:
+ category, name = initial_plugin
+ plugin = get_plugin(category, name)
+ if plugin is not None:
+ self.show_plugin(plugin)
+
+
+ def show_plugin(self, plugin):
+ self.showing_widget = plugin.create_widget(self.scroll_area)
+ self.showing_widget.genesis(self.gui)
+ self.showing_widget.initialize()
+ self.scroll_area.setWidget(self.showing_widget)
+ self.stack.setCurrentIndex(1)
+ self.showing_widget.show()
+ self.setWindowTitle(__appname__ + ' - ' + _('Preferences') + ' - ' +
+ plugin.gui_name)
+ self.apply_action.setEnabled(False)
+ self.showing_widget.changed_signal.connect(lambda :
+ self.apply_action.setEnabled(True))
+ self.restore_action.setEnabled(self.showing_widget.supports_restoring_to_defaults)
+ tt = self.showing_widget.restore_defaults_desc
+ if not self.restore_action.isEnabled():
+ tt = _('Restoring to defaults not supported for') + ' ' + \
+ plugin.gui_name
+ self.restore_action.setToolTip(textwrap.fill(tt))
+ self.restore_action.setWhatsThis(textwrap.fill(tt))
+ self.restore_action.setStatusTip(tt)
+ self.bar_filler.setText(plugin.gui_name)
+ self.setWindowIcon(QIcon(plugin.icon))
+ self.bar.setVisible(True)
+
+
+ def hide_plugin(self):
+ self.showing_widget = QWidget(self.scroll_area)
+ self.scroll_area.setWidget(self.showing_widget)
+ self.setWindowTitle(__appname__ + ' - ' + _('Preferences'))
+ self.bar.setVisible(False)
+ self.stack.setCurrentIndex(0)
+ self.setWindowIcon(QIcon(I('config.png')))
+
+ def esc(self, *args):
+ if self.stack.currentIndex() == 1:
+ self.hide_plugin()
+ elif self.stack.currentIndex() == 0:
+ self.close()
+
+ def commit(self, *args):
+ try:
+ must_restart = self.showing_widget.commit()
+ except AbortCommit:
+ return
+ self.committed = True
+ if must_restart:
+ self.must_restart = True
+ warning_dialog(self, _('Restart needed'),
+ _('Some of the changes you made require a restart.'
+ ' Please restart calibre as soon as possible.'),
+ show=True, show_copy_button=False)
+ self.showing_widget.refresh_gui(self.gui)
+ self.hide_plugin()
+
+
+ def cancel(self, *args):
+ self.hide_plugin()
+
+ def restore_defaults(self, *args):
+ self.showing_widget.restore_defaults()
+
+ def closeEvent(self, *args):
+ gprefs.set('preferences_window_geometry',
+ bytearray(self.saveGeometry()))
+ return QMainWindow.closeEvent(self, *args)
+
+if __name__ == '__main__':
+ from PyQt4.Qt import QApplication
+ app = QApplication([])
+ app
+ gui = init_gui()
+
+ p = Preferences(gui)
+ p.show()
+ app.exec_()
+ gui.shutdown()
diff --git a/src/calibre/gui2/preferences/misc.py b/src/calibre/gui2/preferences/misc.py
new file mode 100644
index 0000000000..eae79fdfc0
--- /dev/null
+++ b/src/calibre/gui2/preferences/misc.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+
+__license__ = 'GPL v3'
+__copyright__ = '2010, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+from PyQt4.Qt import QProgressDialog, QThread, Qt, pyqtSignal
+
+from calibre.gui2.preferences import ConfigWidgetBase, test_widget
+from calibre.gui2.preferences.misc_ui import Ui_Form
+from calibre.gui2 import error_dialog, config, warning_dialog, \
+ open_local_file, info_dialog
+from calibre.constants import isosx
+
+# Check Integrity {{{
+
+class VacThread(QThread):
+
+ check_done = pyqtSignal(object, object)
+ callback = pyqtSignal(object, object)
+
+ def __init__(self, parent, db):
+ QThread.__init__(self, parent)
+ self.db = db
+ self._parent = parent
+
+ def run(self):
+ err = bad = None
+ try:
+ bad = self.db.check_integrity(self.callbackf)
+ except:
+ import traceback
+ err = traceback.format_exc()
+ self.check_done.emit(bad, err)
+
+ def callbackf(self, progress, msg):
+ self.callback.emit(progress, msg)
+
+
+class CheckIntegrity(QProgressDialog):
+
+ def __init__(self, db, parent=None):
+ QProgressDialog.__init__(self, parent)
+ self.db = db
+ self.setCancelButton(None)
+ self.setMinimum(0)
+ self.setMaximum(100)
+ self.setWindowTitle(_('Checking database integrity'))
+ self.setAutoReset(False)
+ self.setValue(0)
+
+ self.vthread = VacThread(self, db)
+ self.vthread.check_done.connect(self.check_done,
+ type=Qt.QueuedConnection)
+ self.vthread.callback.connect(self.callback, type=Qt.QueuedConnection)
+ self.vthread.start()
+
+ def callback(self, progress, msg):
+ self.setLabelText(msg)
+ self.setValue(int(100*progress))
+
+ def check_done(self, bad, err):
+ if err:
+ error_dialog(self, _('Error'),
+ _('Failed to check database integrity'),
+ det_msg=err, show=True)
+ elif bad:
+ titles = [self.db.title(x, index_is_id=True) for x in bad]
+ det_msg = '\n'.join(titles)
+ warning_dialog(self, _('Some inconsistencies found'),
+ _('The following books had formats listed in the '
+ 'database that are not actually available. '
+ 'The entries for the formats have been removed. '
+ 'You should check them manually. This can '
+ 'happen if you manipulate the files in the '
+ 'library folder directly.'), det_msg=det_msg, show=True)
+ self.reset()
+
+# }}}
+
+class ConfigWidget(ConfigWidgetBase, Ui_Form):
+
+ def genesis(self, gui):
+ self.gui = gui
+ r = self.register
+ r('worker_limit', config, restart_required=True)
+ r('enforce_cpu_limit', config, restart_required=True)
+ self.device_detection_button.clicked.connect(self.debug_device_detection)
+ self.compact_button.clicked.connect(self.compact)
+ self.button_open_config_dir.clicked.connect(self.open_config_dir)
+ self.button_osx_symlinks.clicked.connect(self.create_symlinks)
+ self.button_osx_symlinks.setVisible(isosx)
+
+ def debug_device_detection(self, *args):
+ from calibre.gui2.preferences.device_debug import DebugDevice
+ d = DebugDevice(self)
+ d.exec_()
+
+ def compact(self, *args):
+ d = CheckIntegrity(self.gui.library_view.model().db, self)
+ d.exec_()
+
+ def open_config_dir(self, *args):
+ from calibre.utils.config import config_dir
+ open_local_file(config_dir)
+
+ def create_symlinks(self):
+ from calibre.utils.osx_symlinks import create_symlinks
+ loc, paths = create_symlinks()
+ if loc is None:
+ error_dialog(self, _('Error'),
+ _('Failed to install command line tools.'),
+ det_msg=paths, show=True)
+ else:
+ info_dialog(self, _('Command line tools installed'),
+ '
'+_('Command line tools installed in')+' '+loc+
+ ' '+ _('If you move calibre.app, you have to re-install '
+ 'the command line tools.'),
+ det_msg='\n'.join(paths), show=True)
+
+
+if __name__ == '__main__':
+ from PyQt4.Qt import QApplication
+ app = QApplication([])
+ test_widget('Advanced', 'Misc')
+
diff --git a/src/calibre/gui2/preferences/misc.ui b/src/calibre/gui2/preferences/misc.ui
new file mode 100644
index 0000000000..f8582a3675
--- /dev/null
+++ b/src/calibre/gui2/preferences/misc.ui
@@ -0,0 +1,144 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 502
+ 314
+
+
+
+ Form
+
+
+
+
+
+ &Maximum number of waiting worker processes (needs restart):
+
+
+ opt_worker_limit
+
+
+
+
+
+
+ 2
+
+
+ 10000
+
+
+ 2
+
+
+
+
+
+
+ Limit the max. simultaneous jobs to the available CPU &cores
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 18
+
+
+
+
+
+
+
+ Debug &device detection
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 19
+
+
+
+
+
+
+
+ &Check database integrity
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 18
+
+
+
+
+
+
+
+ Open calibre &configuration directory
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 19
+
+
+
+
+
+
+
+ &Install command line tools
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 18
+
+
+
+
+
+
+
+
+
diff --git a/src/calibre/gui2/preferences/saving.py b/src/calibre/gui2/preferences/saving.py
index a698083475..e4b6a33917 100644
--- a/src/calibre/gui2/preferences/saving.py
+++ b/src/calibre/gui2/preferences/saving.py
@@ -45,6 +45,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.save_template.save_settings(self.proxy, 'template')
return ConfigWidgetBase.commit(self)
+ def refresh_gui(self, gui):
+ gui.iactions['Save To Disk'].reread_prefs()
+
+
if __name__ == '__main__':
from PyQt4.Qt import QApplication
app = QApplication([])
diff --git a/src/calibre/gui2/preferences/server.py b/src/calibre/gui2/preferences/server.py
index 6777b4c49a..4db1244d75 100644
--- a/src/calibre/gui2/preferences/server.py
+++ b/src/calibre/gui2/preferences/server.py
@@ -15,7 +15,8 @@ from calibre.gui2.preferences.server_ui import Ui_Form
from calibre.utils.search_query_parser import saved_searches
from calibre.library.server import server_config
from calibre.utils.config import ConfigProxy
-from calibre.gui2 import error_dialog, config, open_url, warning_dialog
+from calibre.gui2 import error_dialog, config, open_url, warning_dialog, \
+ Dispatcher
class ConfigWidget(ConfigWidgetBase, Ui_Form):
@@ -121,6 +122,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
' take effect'), show=True)
return False
+ def refresh_gui(self, gui):
+ gui.content_server = self.server
+ if gui.content_server is not None:
+ gui.content_server.state_callback = \
+ Dispatcher(gui.iactions['Connect Share'].content_server_state_changed)
+ gui.content_server.state_callback(gui.content_server.is_running)
+
if __name__ == '__main__':
from PyQt4.Qt import QApplication
diff --git a/src/calibre/gui2/dialogs/config/social.py b/src/calibre/gui2/preferences/social.py
similarity index 100%
rename from src/calibre/gui2/dialogs/config/social.py
rename to src/calibre/gui2/preferences/social.py
diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py
index 84f5a1a2c9..624935f279 100644
--- a/src/calibre/gui2/ui.py
+++ b/src/calibre/gui2/ui.py
@@ -522,6 +522,12 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
def shutdown(self, write_settings=True):
+ try:
+ cf = self.library_view.model().db.clean
+ except:
+ pass
+ else:
+ cf()
for action in self.iactions.values():
if not action.shutting_down():
return
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index 0237da0a09..60224aefc7 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -1032,6 +1032,9 @@ class Splitter(QSplitter):
# Public API {{{
+ def update_desired_state(self):
+ self.desired_show = not self.is_side_index_hidden
+
def save_state(self):
if self.count() > 1:
gprefs[self.save_name+'_state'] = self.get_state()
diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py
index 4b5cb6bb84..75e51ff3ca 100644
--- a/src/calibre/library/catalog.py
+++ b/src/calibre/library/catalog.py
@@ -104,6 +104,8 @@ class CSV_XML(CatalogPlugin):
# Output the entry fields
for entry in data:
+ print "%s [%s]" % (entry['title'],entry['id'])
+ print "ondevice: %s" % db.ondevice(entry['id'], index_is_id=True)
outstr = []
for field in fields:
item = entry[field]
diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py
index 3c2e7c09cd..ad9cda07b8 100644
--- a/src/calibre/library/cli.py
+++ b/src/calibre/library/cli.py
@@ -324,6 +324,7 @@ def do_remove(db, ids):
db.delete_book(y)
send_message()
+ db.clean()
def remove_option_parser():
return get_parser(_(
@@ -449,6 +450,7 @@ def command_show_metadata(args, dbpath):
def do_set_metadata(db, id, stream):
mi = OPF(stream)
db.set_metadata(id, mi)
+ db.clean()
do_show_metadata(db, id, False)
send_message()
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index 4b6fb2f7f2..23ec60d320 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -144,6 +144,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.initialize_dynamic()
def initialize_dynamic(self):
+ self.field_metadata = FieldMetadata() #Ensure we start with a clean copy
self.prefs = DBPrefs(self)
defs = self.prefs.defaults
defs['gui_restriction'] = defs['cs_restriction'] = ''
@@ -331,7 +332,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
for prop in ('author_sort', 'authors', 'comment', 'comments', 'isbn',
'publisher', 'rating', 'series', 'series_index', 'tags',
- 'title', 'timestamp', 'uuid', 'pubdate'):
+ 'title', 'timestamp', 'uuid', 'pubdate', 'ondevice'):
setattr(self, prop, functools.partial(get_property,
loc=self.FIELD_MAP['comments' if prop == 'comment' else prop]))
setattr(self, 'title_sort', functools.partial(get_property,
@@ -1125,7 +1126,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if not authors:
authors = [_('Unknown')]
self.conn.execute('DELETE FROM books_authors_link WHERE book=?',(id,))
- self.conn.execute('DELETE FROM authors WHERE (SELECT COUNT(id) FROM books_authors_link WHERE author=authors.id) < 1')
for a in authors:
if not a:
continue
@@ -2151,8 +2151,6 @@ books_series_link feeds
os.remove(self.dbpath)
shutil.copyfile(dest, self.dbpath)
self.connect()
- self.field_metadata.remove_dynamic_categories()
- self.field_metadata.remove_custom_fields()
self.initialize_dynamic()
self.refresh()
if os.path.exists(dest):
diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py
index e28b6d422a..09dd024b66 100644
--- a/src/calibre/library/field_metadata.py
+++ b/src/calibre/library/field_metadata.py
@@ -306,7 +306,7 @@ class FieldMetadata(dict):
self._tb_cats[k]['label'] = k
self._tb_cats[k]['display'] = {}
self._tb_cats[k]['is_editable'] = True
- self._add_search_terms_to_map(k, self._tb_cats[k]['search_terms'])
+ self._add_search_terms_to_map(k, v['search_terms'])
self.custom_field_prefix = '#'
self.get = self._tb_cats.get
@@ -408,16 +408,6 @@ class FieldMetadata(dict):
self._add_search_terms_to_map(key, [key])
self.custom_label_to_key_map[label+'_index'] = key
- def remove_custom_fields(self):
- for key in self.get_custom_fields():
- del self._tb_cats[key]
-
- def remove_dynamic_categories(self):
- for key in list(self._tb_cats.keys()):
- val = self._tb_cats[key]
- if val['is_category'] and val['kind'] in ('user', 'search'):
- del self._tb_cats[key]
-
def cc_series_index_column_for(self, key):
return self._tb_cats[key]['rec_index'] + 1
diff --git a/src/calibre/manual/gui.rst b/src/calibre/manual/gui.rst
index e9573e91be..aa49c51b76 100644
--- a/src/calibre/manual/gui.rst
+++ b/src/calibre/manual/gui.rst
@@ -345,6 +345,8 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes
- Show book details
* - :kbd:`M`
- Merge selected records
+ * - :kbd:`Alt+M`
+ - Merge selected records, keeping originals
* - :kbd:`O`
- Open containing folder
* - :kbd:`S`
diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot
index 4cf17d66e9..116d4d6fce 100644
--- a/src/calibre/translations/calibre.pot
+++ b/src/calibre/translations/calibre.pot
@@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: calibre 0.7.17\n"
-"POT-Creation-Date: 2010-09-03 12:17+MDT\n"
-"PO-Revision-Date: 2010-09-03 12:17+MDT\n"
+"POT-Creation-Date: 2010-09-05 17:35+MDT\n"
+"PO-Revision-Date: 2010-09-05 17:35+MDT\n"
"Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n"
@@ -107,14 +107,14 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:292
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:137
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:144
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/__init__.py:41
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/__init__.py:42
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:111
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:136
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:138
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:869
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:878
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1163
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1166
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:862
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:871
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1155
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1158
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:47
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:155
@@ -176,8 +176,10 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:376
#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:17
#: /home/kovid/work/calibre/src/calibre/gui2/actions/preferences.py:22
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:612
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:201
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:150
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:213
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/main.py:234
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:206
msgid "Preferences"
msgstr ""
@@ -239,20 +241,156 @@ msgstr ""
msgid "Set metadata from %s files"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:681
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:682
msgid "Look and Feel"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:683
-#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:692
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:199
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:684
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:696
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:707
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:718
msgid "Interface"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:690
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:688
+msgid "Adjust the look and feel of the calibre interface to suit your tastes"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:694
msgid "Behavior"
msgstr ""
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:700
+msgid "Change the way calibre behaves"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:705
+msgid "Add your own columns"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:711
+msgid "Add/remove your own columns to the calibre book list"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:716
+msgid "Customize the toolbar"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:722
+msgid "Customize the toolbars and context menus, changing which actions are available in each"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:728
+msgid "Input Options"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:730
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:741
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:752
+msgid "Conversion"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:734
+msgid "Set conversion options specific to each input format"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:739
+msgid "Common Options"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:745
+msgid "Set conversion options common to all formats"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:750
+msgid "Output Options"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:756
+msgid "Set conversion options specific to each output format"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:761
+msgid "Adding books"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:763
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:775
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:787
+msgid "Import/Export"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:767
+msgid "Control how calibre reads metadata from files when adding books"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:773
+msgid "Saving books to disk"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:779
+msgid "Control how calibre exports files from its database to disk when using Save to disk"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:785
+msgid "Sending books to devices"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:791
+msgid "Control how calibre transfers files to your ebook reader"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:797
+msgid "Sharing books by email"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:799
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811
+msgid "Sharing"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:803
+msgid "Setup sharing of books via email. Can be used for automatic sending of downloaded news to your devices"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:809
+msgid "Sharing over the net"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:815
+msgid "Setup the calibre Content Server which will give you access to your calibre library from anywhere, on any device, over the internet"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:822
+msgid "Plugins"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:824
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:836
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:847
+msgid "Advanced"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:828
+msgid "Add/remove/customize various bits of calibre functionality"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:834
+msgid "Tweaks"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:840
+msgid "Fine tune how calibre behaves in various contexts"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:845
+msgid "Miscellaneous"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:851
+msgid "Miscellaneous advanced configuration"
+msgstr ""
+
#: /home/kovid/work/calibre/src/calibre/customize/conversion.py:102
msgid "Conversion Input"
msgstr ""
@@ -832,7 +970,7 @@ msgid "Place files in sub directories if the device supports them"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/usbms/deviceconfig.py:43
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:81
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:86
msgid "Read metadata from files on device"
msgstr ""
@@ -845,7 +983,7 @@ msgid "Template to control how books are saved"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/usbms/deviceconfig.py:50
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:84
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:89
msgid "Extra customization"
msgstr ""
@@ -1678,9 +1816,9 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:35
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:210
#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:211
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:184
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:189
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:99
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:67
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:72
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:318
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1079
msgid "Comments"
@@ -1977,7 +2115,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1401
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/htmltoc.py:15
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:53
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:194
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:199
msgid "Table of Contents"
msgstr ""
@@ -2611,7 +2749,7 @@ msgid "Add books to your calibre library from the connected device"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/annotate.py:20
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:499
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:498
msgid "Fetch annotations (experimental)"
msgstr ""
@@ -2702,7 +2840,7 @@ msgid "Select destination for %s.%s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:81
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:50
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar.py:51
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:111
msgid "%d books"
msgstr ""
@@ -2749,8 +2887,8 @@ msgid "The folder %s already exists. Delete it first."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:186
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:753
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:48
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:53
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns.py:100
msgid "Are you sure?"
msgstr ""
@@ -2835,7 +2973,7 @@ msgid "Could not copy books: "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:137
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:678
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:671
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:234
msgid "Failed"
msgstr ""
@@ -2897,14 +3035,14 @@ msgid "Main memory"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:115
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:436
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:445
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:435
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:444
msgid "Storage Card A"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:116
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:438
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:447
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:437
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:446
msgid "Storage Card B"
msgstr ""
@@ -3061,9 +3199,9 @@ msgid "Failed to download metadata:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:129
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:608
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:570
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:1005
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:607
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc.py:65
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc.py:112
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:54
msgid "Error"
msgstr ""
@@ -3327,7 +3465,7 @@ msgid "The specified directory could not be processed."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:228
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:811
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:804
msgid "No books"
msgstr ""
@@ -3376,7 +3514,7 @@ msgid "Looking for duplicates based on file hash"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/__init__.py:109
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:65
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:70
msgid "Choose root folder"
msgstr ""
@@ -3393,7 +3531,7 @@ msgid "Add books to calibre"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/scan_ui.py:21
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:57
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:62
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/finish_ui.py:41
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/kindle_ui.py:41
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/library_ui.py:49
@@ -3409,94 +3547,92 @@ msgstr ""
msgid "This may take a few minutes"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:58
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:63
msgid "Choose the location to add books from"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:59
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:64
msgid "Select a folder on your hard disk"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:60
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:65
msgid ""
"
calibre can scan your computer for existing books automatically. These books will then be copied into the calibre library. This wizard will help you customize the scanning and import process for your existing book collection.
\n"
"
Choose a root folder. Books will be searched for only inside this folder and any sub-folders.
\n"
"
Make sure that the folder you chose for your calibre library is not under the root folder you choose.
"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:63
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:68
msgid "&Root folder:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:64
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:69
msgid "This folder and its sub-folders will be scanned for books to import into calibre's library"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:66
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:52
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:53
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:125
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:53
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:79
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:80
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:72
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:629
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:630
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:642
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:644
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:646
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:648
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:649
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:702
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:101
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:103
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:106
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:108
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:364
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:71
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:57
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:58
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:130
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:176
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:58
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:84
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:85
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:77
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:369
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:383
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:394
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:396
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:398
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:404
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:87
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:90
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:156
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:159
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:163
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:166
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:126
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:128
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:374
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:388
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:399
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:401
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:403
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:409
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:92
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:95
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:161
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:164
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:168
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:171
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:131
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:135
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:75
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:77
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:267
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:269
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:270
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:133
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:136
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:140
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:80
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:82
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:272
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:274
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:275
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:156
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:157
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:78
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:80
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:82
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:84
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns_ui.py:83
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns_ui.py:85
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns_ui.py:87
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns_ui.py:89
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns_ui.py:90
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:83
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:85
-#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:75
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:87
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:89
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:90
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins_ui.py:88
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:103
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:105
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:108
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:110
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:80
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:186
+#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:85
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:191
msgid "..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:67
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:72
msgid "Handle multiple files per book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:68
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:73
msgid "&One book per folder, assumes every ebook file in a folder is the same book in a different format"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:69
+#: /home/kovid/work/calibre/src/calibre/gui2/add_wizard/welcome_ui.py:74
msgid "&Multiple books per folder, assumes every ebook file is a different book"
msgstr ""
@@ -3520,8 +3656,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:118
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:119
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:122
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:229
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:312
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:24
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:100
msgid "Formats"
msgstr ""
@@ -3544,9 +3680,9 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1074
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1078
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:47
-#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:73
#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:78
-#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:282
+#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:83
+#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:293
msgid "None"
msgstr ""
@@ -3596,13 +3732,13 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:68
#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_tab_template_ui.py:27
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:88
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:49
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:54
#: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:48
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input_ui.py:28
#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:31
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:119
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:124
#: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:115
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:166
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171
#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output_ui.py:66
#: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup_ui.py:115
#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_input_ui.py:31
@@ -3614,16 +3750,26 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/toc_ui.py:62
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_input_ui.py:46
#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:45
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:50
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:55
#: /home/kovid/work/calibre/src/calibre/gui2/convert/xpath_wizard_ui.py:67
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:77
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/save_template_ui.py:41
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:96
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:82
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_item_ui.py:35
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:106
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/adding_ui.py:48
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:136
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:76
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/columns_ui.py:81
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/conversion_ui.py:54
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:81
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/email_ui.py:65
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:97
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/misc_ui.py:63
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins_ui.py:81
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template_ui.py:46
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/saving_ui.py:67
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/sending_ui.py:61
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/server_ui.py:123
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:98
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/tweaks_ui.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:107
msgid "Form"
msgstr ""
@@ -3785,52 +3931,52 @@ msgid "input"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:89
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:94
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:99
msgid "&Number of Colors:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:90
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:101
msgid "Disable &normalize"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:91
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:102
msgid "Keep &aspect ratio"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:92
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:103
msgid "Disable &Sharpening"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:93
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:104
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:109
msgid "Disable &Trimming"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:94
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:103
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:108
msgid "&Wide"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:95
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:99
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:104
msgid "&Landscape"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:96
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:101
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:106
msgid "&Right to left"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:97
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:100
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:105
msgid "Don't so&rt"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:98
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:102
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:107
msgid "De&speckle"
msgstr ""
@@ -3839,7 +3985,7 @@ msgid "&Disable comic processing"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/comic_input_ui.py:100
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:115
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:120
msgid "&Output format:"
msgstr ""
@@ -3856,7 +4002,7 @@ msgid "Debug the conversion process."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug.py:39
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:51
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:56
msgid "Choose debug folder"
msgstr ""
@@ -3868,11 +4014,11 @@ msgstr ""
msgid "Failed to create debug directory"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:50
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:55
msgid "Choose a folder to put the debug output into. If you specify a folder, calibre will place a lot of debug output into it. This will be useful in understanding the conversion process and figuring out the correct values for conversion parameters like Table of Contents and Chapter Detection."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:54
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:59
msgid "The debug process outputs the intermediate HTML generated at various stages of the conversion process. This HTML can sometimes serve as a good starting point for hand editing a conversion."
msgstr ""
@@ -3927,36 +4073,36 @@ msgstr ""
msgid "Sectionize Chapters (Use with care!)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:99
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:104
msgid "Font rescaling wizard"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:100
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/font_key_ui.py:105
msgid ""
"
This wizard will help you choose an appropriate font size key for your needs. Just enter the base font size of the input document and then enter an input font size. The wizard will display what font size it will be mapped to, by the font rescaling algorithm. You can adjust the algorithm by adjusting the output base font size and font key below. When you find values suitable for you, click OK.
\n"
"
By default, if the output base font size is zero and/or no font size key is specified, calibre will use the values from the current Output Profile.
\n"
"
See the User Manual for a discussion of how font size rescaling works.
When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:132
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:137
msgid " em"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:133
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:138
msgid "Text justification:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:134
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:139
msgid "&Linearize tables"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:135
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:140
msgid "Extra &CSS"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:136
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:141
msgid "&Transliterate unicode characters to ASCII"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:137
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:142
msgid "Insert &blank line"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:138
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:143
msgid "Keep &ligatures"
msgstr ""
@@ -4121,7 +4267,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:41
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:114
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:195
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:200
msgid "Metadata"
msgstr ""
@@ -4160,82 +4306,82 @@ msgstr ""
msgid " is not a valid picture"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:167
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:400
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:172
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:405
msgid "Book Cover"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:168
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:173
msgid "Use cover from &source file"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:169
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:401
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:174
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:406
msgid "Change &cover image:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:170
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:175
msgid "Browse for an image to use as the cover of this book."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:172
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:361
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:177
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:366
msgid "&Title: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:173
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:362
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:178
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:367
msgid "Change the title of this book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:174
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:161
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:365
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:179
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:166
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:370
msgid "&Author(s): "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:175
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:180
msgid "Author So&rt:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:176
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:181
msgid "Change the author(s) of this book. Multiple authors should be separated by a comma"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:177
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:170
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:374
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:182
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:175
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:379
msgid "&Publisher: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:178
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:375
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:183
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:380
msgid "Ta&gs: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:179
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:172
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:376
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:184
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:177
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:381
msgid "Tags categorize the book. This is particularly useful while searching.
They can be any words or phrases, separated by commas."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:180
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:179
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:379
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:185
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:184
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:384
msgid "&Series:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:181
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:182
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:180
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:181
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:380
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:381
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:186
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:187
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:185
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:186
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:385
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:386
msgid "List of known series. You can add new series."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:183
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:386
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:188
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:391
msgid "Book "
msgstr ""
@@ -4243,7 +4389,7 @@ msgstr ""
msgid "MOBI Output"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:42
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/mobi_output.py:43
msgid "Default"
msgstr ""
@@ -4406,18 +4552,18 @@ msgstr ""
msgid "Options specific to the input format."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:112
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:64
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:91
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:48
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:117
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:69
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:53
msgid "Dialog"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:113
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:118
msgid "&Input format:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:114
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/single_ui.py:119
msgid "Use &saved conversion settings for individual books"
msgstr ""
@@ -4448,12 +4594,12 @@ msgid "Footer regular expression:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:57
-#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:76
+#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:87
msgid "Invalid regular expression"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:58
-#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:77
+#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:88
msgid "Invalid regular expression: %s"
msgstr ""
@@ -4575,18 +4721,18 @@ msgstr ""
msgid "Force maximum line length"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:51
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:65
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:66
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:41
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:49
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:57
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:49
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:50
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:56
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:70
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:71
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:46
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:54
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:62
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:54
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:55
msgid "TextLabel"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:52
+#: /home/kovid/work/calibre/src/calibre/gui2/convert/xexp_edit_ui.py:57
msgid "Use a wizard to help construct the XPath expression"
msgstr ""
@@ -4681,16 +4827,12 @@ msgid "Undefined"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:59
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:131
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:133
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:241
#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:119
msgid "Yes"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:59
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:132
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:134
#: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:243
#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:121
msgid "No"
@@ -4713,7 +4855,7 @@ msgid " index:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:451
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:188
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:193
msgid "Automatically number books in this series"
msgstr ""
@@ -4729,267 +4871,267 @@ msgstr ""
msgid "tags to remove"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:49
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:48
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:136
msgid "No details available."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:166
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:165
msgid "Device no longer connected."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:284
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:283
msgid "Get device information"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:295
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:294
msgid "Get list of books on device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:305
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:304
msgid "Get annotations from device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:314
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:313
msgid "Send metadata to device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:319
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:318
msgid "Send collections to device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:343
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:342
msgid "Upload %d books to device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:358
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:357
msgid "Delete books from device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:375
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:374
msgid "Download books from device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:385
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:384
msgid "View book on device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:419
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:418
msgid "Set default send to device action"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:425
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:424
msgid "Send to main memory"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:427
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:426
msgid "Send to storage card A"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:429
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:428
msgid "Send to storage card B"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:434
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:443
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:433
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:442
msgid "Main Memory"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:454
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:453
msgid "Send and delete from library"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:455
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:454
msgid "Send specific format"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:491
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:490
msgid "Eject device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:609
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:608
msgid "Error communicating with device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:636
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:629
msgid "Select folder to open as device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:684
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:677
msgid "Error talking to device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:685
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:678
msgid "There was a temporary error talking to the device. Please unplug and reconnect the device and or reboot."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:724
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:717
msgid "Device: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:726
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:719
msgid " detected."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:812
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:805
msgid "selected to send"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:817
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:810
msgid "Choose format to send to device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:826
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:819
msgid "No device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:827
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:820
msgid "Cannot send: No device is connected"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:830
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:834
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:823
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:827
msgid "No card"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:831
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:835
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:824
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:828
msgid "Cannot send: Device has no storage card"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:876
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:869
msgid "E-book:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:879
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:872
msgid "Attached, you will find the e-book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:880
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:180
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:873
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:107
msgid "by"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:881
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:874
msgid "in the %s format."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:894
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:887
msgid "Sending email to"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:924
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:932
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1026
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1088
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:917
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:925
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1018
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1080
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1199
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1207
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1215
msgid "No suitable formats"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:925
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:918
msgid "Auto convert the following books before sending via email?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:933
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:926
msgid "Could not email the following books as no suitable formats were found:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:951
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:944
msgid "Failed to email books"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:952
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:945
msgid "Failed to email the following books:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:956
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:949
msgid "Sent by email:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:985
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:977
msgid "News:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:986
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:978
msgid "Attached is the"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:997
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:989
msgid "Sent news to"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1027
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1089
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1208
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1019
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1081
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1200
msgid "Auto convert the following books before uploading to the device?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1057
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1049
msgid "Sending catalogs to device."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1121
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1113
msgid "Sending news to device."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1174
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1166
msgid "Sending books to device."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1216
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1208
msgid "Could not upload the following books to the device, as no suitable formats were found. Convert the book(s) to a format supported by your device first."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1278
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1270
msgid "No space on device"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1279
+#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1271
msgid "
Cannot upload books to device there is no more free space available "
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:78
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:83
msgid "Select available formats and their order for this device"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:82
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:87
msgid "Use sub directories"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:83
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:88
msgid "Use author sort for author"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:85
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget_ui.py:90
msgid "Save &template:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_from_isbn_ui.py:43
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_from_isbn_ui.py:48
msgid "Add books by ISBN"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_from_isbn_ui.py:44
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_from_isbn_ui.py:49
msgid "
Enter a list of ISBNs in the box to the left, one per line. calibre will automatically create entries for books based on the ISBN and download metadata and covers for them.
Any invalid ISBNs in the list will be ignored."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_from_isbn_ui.py:45
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/add_from_isbn_ui.py:50
msgid "&Paste from clipboard"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:68
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:73
msgid "Fit &cover within view"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:69
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:74
msgid "&Previous"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:70
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:75
msgid "&Next"
msgstr ""
@@ -5022,7 +5164,7 @@ msgstr ""
msgid "Catalog options"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:40
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:45
msgid "Choose Format"
msgstr ""
@@ -5070,27 +5212,27 @@ msgstr ""
msgid "%s is not an existing folder"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:66
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:71
msgid "Choose your calibre library"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:67
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:72
msgid "Your calibre library is currently located at {0}"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:68
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:73
msgid "New &Location:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:69
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:74
msgid "Use &existing library at the new location"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:70
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:75
msgid "&Create an empty library at the new location"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:71
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:76
msgid "&Move current library to new location"
msgstr ""
@@ -5102,15 +5244,15 @@ msgstr ""
msgid "Set options for converting %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:92
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97
msgid "&Title:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:93
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98
msgid "&Author(s):"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:95
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:100
msgid "&Profile:"
msgstr ""
@@ -5118,1081 +5260,11 @@ msgstr ""
msgid "Edit Comments"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:173
-msgid "%(plugin_type)s %(plugins)s"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:174
-msgid "plugins"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:183
-msgid ""
-"\n"
-"Customization: "
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:198
-msgid "General"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:200
-msgid "Conversion"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:201
-msgid ""
-"Email\n"
-"Delivery"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:202
-msgid "Add/Save"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:203
-msgid "Advanced"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:204
-msgid ""
-"Content\n"
-"Server"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:205
-msgid "Plugins"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:229
-msgid "Auto send"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:229
-msgid "Email"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:234
-msgid "Formats to email. The first matching format will be sent."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:235
-msgid "If checked, downloaded news will be automatically mailed to this email address (provided it is in one of the listed formats)."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:309
-msgid "new email address"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:492
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:24
-msgid "Wide"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:493
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:24
-msgid "Narrow"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:509
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:50
-msgid "Medium"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:509
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:50
-msgid "Small"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:510
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:51
-msgid "Large"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:516
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:54
-msgid "Always"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:516
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:54
-msgid "Automatic"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:517
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:55
-msgid "Never"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:530
-msgid "Toolbars/Context menus"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:544
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:156
-msgid "Done"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:545
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:157
-msgid "Confirmation dialogs have all been reset"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:550
-msgid "System port selected"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:551
-msgid "The value %d you have chosen for the content server port is a system port. Your operating system may not allow the server to run on this port. To be safe choose a port number larger than 1024."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:571
-msgid "Failed to install command line tools."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:574
-msgid "Command line tools installed"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:575
-msgid "Command line tools installed in"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:576
-msgid "If you move calibre.app, you have to re-install the command line tools."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:627
-msgid "No valid plugin path"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:628
-msgid "%s is not a valid plugin path"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:631
-msgid "Choose plugin"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:643
-msgid "Plugin cannot be disabled"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:644
-msgid "The plugin: %s cannot be disabled"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:653
-msgid "Plugin not customizable"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:654
-msgid "Plugin: %s does not need customization"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:662
-msgid "Customize"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:700
-msgid "Cannot remove builtin plugin"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:701
-msgid " cannot be removed. It is a builtin plugin. Try disabling it instead."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:716
-msgid "Invalid tweaks"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:717
-msgid "The tweaks you entered are invalid, try resetting the tweaks to default and changing them one by one until you find the invalid setting."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:747
-msgid "You must select a column to delete it"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:752
-msgid "The selected column is not a custom column"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:754
-msgid "Do you really want to delete column %s and all its data?"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:821
-msgid "Error log:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:828
-msgid "Access log:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:856
-#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:319
-msgid "Failed to start content server"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:881
-msgid "Invalid size"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:882
-msgid "The size %s is invalid. must be of the form widthxheight"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:951
-msgid "Must restart"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:952
-msgid "The changes you made require that Calibre be restarted. Please restart as soon as practical."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:986
-msgid "Checking database integrity"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:1006
-msgid "Failed to check database integrity"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:1011
-msgid "Some inconsistencies found"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:1012
-msgid "The following books had formats listed in the database that are not actually available. The entries for the formats have been removed. You should check them manually. This can happen if you manipulate the files in the library folder directly."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:133
-msgid "TabWidget"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:134
-msgid "Here you can control how calibre will read metadata from the files you add to it. calibre can either read metadata from the contents of the file, or from the filename."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:135
-msgid "Read metadata only from &file name"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:136
-msgid "Swap the firstname and lastname of the author. This affects only metadata read from file names."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:137
-msgid "&Swap author firstname and lastname"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:138
-msgid ""
-"If an existing book with a similar title and author is found that does not have the format being added, the format is added\n"
-"to the existing book, instead of creating a new entry. If the existing book already has the format, then it is silently ignored.\n"
-"\n"
-"Title match ignores leading indefinite articles (\"the\", \"a\", \"an\"), punctuation, case, etc. Author match is exact."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:142
-msgid "If books with similar titles and authors found, &merge the new files automatically"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:143
-msgid "&Configure metadata from file name"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:144
-msgid "&Adding books"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:145
-msgid "Here you can control how calibre will save your books when you click the Save to Disk button:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:146
-msgid "Save &cover separately"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:147
-msgid "Update &metadata in saved copies"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:148
-msgid "Save metadata in &OPF file"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:149
-msgid "Convert non-English characters to &English equivalents"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:150
-msgid "Format &dates as:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:151
-msgid "File &formats to save:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:152
-msgid "Replace space with &underscores"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:153
-msgid "Change paths to &lowercase"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:154
-msgid "&Saving books"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:155
-msgid "Metadata &management:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:156
-msgid "Manual management"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:157
-msgid "Only on send"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:158
-msgid "Automatic management"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:159
-msgid ""
-"
Manual Management: Calibre updates the metadata and adds collections only when a book is sent. With this option, calibre will never remove a collection.
\n"
-"
Only on send: Calibre updates metadata and adds/removes collections for a book only when it is sent to the device.
\n"
-"
Automatic management: Calibre automatically keeps metadata on the device in sync with the calibre library, on every connect
"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:162
-msgid "Here you can control how calibre will save your books when you click the Send to Device button. This setting can be overriden for individual devices by customizing the device interface plugins in Preferences->Plugins"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:163
-msgid "Sending to &device"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:613
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:139
-msgid "Show notification when &new version is available"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:614
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:138
-msgid "Download &social metadata (tags/ratings/etc.) by default"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:615
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:137
-msgid "&Overwrite author and title by default when fetching metadata"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:616
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:142
-msgid "Default network &timeout:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:617
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:143
-msgid "Set the default timeout for network fetches (i.e. anytime we go out to the internet to get information)"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:618
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:144
-msgid " seconds"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:619
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:100
-msgid "Choose &language (requires restart):"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:620
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:31
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:145
-msgid "Normal"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:621
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:31
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:146
-msgid "High"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:622
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:31
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:147
-msgid "Low"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:623
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:148
-msgid "Job &priority:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:624
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:149
-msgid "Preferred &output format:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:625
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:153
-msgid "Tags to apply when adding a book:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:626
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:152
-msgid "A comma-separated list of tags that will be applied to books added to the library"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:627
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:154
-msgid "Reset all disabled &confirmation dialogs"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:628
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:155
-msgid "Preferred &input format order:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:631
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:98
-msgid "User Interface &layout (needs restart):"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:632
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:99
-msgid "&Number of covers to show in browse mode (needs restart):"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:633
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:150
-msgid "Restriction to apply when the current library is opened:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:634
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:151
-msgid "Apply this restriction on calibre startup if the current library is being used. Also applied when switching to this library. Note that this setting is per library. "
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:635
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:102
-msgid "Disable all animations. Useful if you have a slow/old computer."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:636
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:103
-msgid "Disable &animations"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:637
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:110
-msgid "&Toolbar"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:638
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:111
-msgid "&Icon size:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:639
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:112
-msgid "Show &text under icons:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:640
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:141
-msgid "&Delete news from library when it is automatically sent to reader"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:641
-msgid "Select visible &columns in library view"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:643
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:79
-msgid "Remove a user-defined column"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:645
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:81
-msgid "Add a user-defined column"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:647
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/custom_columns_ui.py:83
-msgid "Edit settings of a user-defined column"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:650
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:158
-msgid "Use internal &viewer for:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:651
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:109
-msgid "Search as you type"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:652
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:107
-msgid "Use &Roman numerals for series"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:653
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:104
-msgid "Enable system &tray icon (needs restart)"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:654
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:101
-msgid "Show &average ratings in the tags browser"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:655
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:140
-msgid "Automatically send downloaded &news to ebook reader"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:656
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:105
-msgid "Show &splash screen at startup"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:657
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:108
-msgid "Show cover &browser in a separate window (needs restart)"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:658
-msgid "Show ¬ifications in system tray"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:659
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:671
-msgid "&Miscellaneous"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:660
-msgid "Add an email address to which to send books"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:661
-msgid "&Add email"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:662
-msgid "Make &default"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:663
-msgid "&Remove email"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:664
-msgid "calibre can send your books to you (or your reader) by email. Emails will be automatically sent for downloaded news to all email addresses that have Auto-send checked."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:665
-msgid "&Maximum number of waiting worker processes (needs restart):"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:666
-msgid "Limit the max. simultaneous jobs to the available CPU &cores"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:667
-msgid "Debug &device detection"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:668
-msgid "&Check database integrity"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:669
-msgid "Open calibre &configuration directory"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:670
-msgid "&Install command line tools"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:672
-msgid "Values for the tweaks are shown below. Edit them to change the behavior of calibre"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:673
-msgid "All available tweaks"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:674
-msgid "&Current tweaks"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:675
-msgid "&Restore to defaults"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:676
-msgid "&Tweaks"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:677
-msgid "calibre contains a network server that allows you to access your book collection using a browser from anywhere in the world. Any changes to the settings will only take effect after a server restart."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:678
-msgid "Server &port:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:679
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:58
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:212
-#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:117
-msgid "&Username:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:680
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:59
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:213
-#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:119
-msgid "&Password:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:681
-msgid "If you leave the password blank, anyone will be able to access your book collection using the web interface."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:682
-msgid "The maximum size (widthxheight) for displayed covers. Larger covers are resized. "
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:683
-msgid "Max. &cover size:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:684
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:60
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:214
-msgid "&Show password"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:685
-msgid "Max. &OPDS items per query:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:686
-msgid "Max. OPDS &ungrouped items:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:687
-msgid "Restriction (saved search) to apply:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:688
-msgid "This restriction (based on a saved search) will restrict the books the content server makes available to those matching the search. This setting is per library (i.e. you can have a different restriction per library)."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:689
-msgid "&Start Server"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:690
-msgid "St&op Server"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:691
-msgid "&Test Server"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:692
-msgid "Run server &automatically on startup"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:693
-msgid "View &server logs"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:694
-#: /home/kovid/work/calibre/src/calibre/gui2/wizard/stanza_ui.py:46
-msgid ""
-"
Remember to leave calibre running as the server only runs as long as calibre is running.\n"
-"
Stanza should see your calibre collection automatically. If not, try adding the URL http://myhostname:8080 as a new catalog in the Stanza reader on your iPhone. Here myhostname should be the fully qualified hostname or the IP address of the computer calibre is running on."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:696
-msgid "Here you can customize the behavior of Calibre by controlling what plugins it uses."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:697
-msgid "Enable/&Disable plugin"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:698
-msgid "&Customize plugin"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:699
-msgid "&Remove plugin"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:700
-msgid "Add new plugin"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:701
-msgid "Plugin &file:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:703
-msgid "&Add"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:125
-msgid "Create Tag-based Column"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:126
-msgid "Lookup name"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:127
-msgid "Column heading"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:128
-msgid "Column type"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:129
-msgid "Use brackets"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:130
-msgid "Values can be edited"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:135
-msgid "Text"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:136
-msgid "Number"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:137
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:31
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:69
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:889
-#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:588
-msgid "Date"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:138
-msgid "Tag on book"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:139
-msgid "Explanation text added in create_ct_column.py"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_ct_column_ui.py:140
-msgid "Create and edit tag-based columns"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:19
-msgid "Text, column shown in the tag browser"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:22
-msgid "Comma separated text, like tags, shown in the tag browser"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:25
-msgid "Long text, like comments, not shown in the tag browser"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:28
-msgid "Text column for keeping series-like information"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:33
-msgid "Floating point numbers"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:35
-msgid "Integers"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:37
-msgid "Ratings, shown with stars"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:40
-msgid "Yes/No"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:69
-msgid "No column selected"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:70
-msgid "No column has been selected"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:74
-msgid "Selected column is not a user-defined column"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:105
-msgid "No lookup name was provided"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:107
-msgid "The lookup name must contain only lower case letters, digits and underscores, and start with a letter"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:109
-msgid "Lookup names cannot end with _index, because these names are reserved for the index of a series column."
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:118
-msgid "No column heading was provided"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:124
-msgid "The lookup name %s is already used"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column.py:134
-msgid "The heading %s is already used"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:101
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:117
-msgid "Create or edit custom columns"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:102
-msgid "&Lookup name"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:103
-msgid "Column &heading"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:104
-msgid "Used for searching the column. Must contain only digits and lower case letters."
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:105
-msgid "Column heading in the library view and category name in the tag browser"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:106
-msgid "Column &type"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:107
-msgid "What kind of information will be kept in the column."
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:108
-msgid ""
-"
Date format. Use 1-4 'd's for day, 1-4 'M's for month, and 2 or 4 'y's for year.
\n"
-"
For example:\n"
-"
\n"
-"
ddd, d MMM yyyy gives Mon, 5 Jan 2010
\n"
-"
dd MMMM yy gives 05 January 10
\n"
-"
"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:114
-msgid "Use MMM yyyy for month + year, yyyy for year only"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:115
-msgid "Default: dd MMM yyyy."
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/create_custom_column_ui.py:116
-msgid "Format for &dates"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/device_debug.py:21
-msgid "Getting debug information"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/device_debug.py:22
-msgid "Copy to &clipboard"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/device_debug.py:24
-msgid "Debug device detection"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/save_template.py:44
-msgid "Invalid template"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/save_template.py:45
-msgid "The template %s is invalid:"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/save_template_ui.py:42
-msgid "Save &template"
-msgstr ""
-
-#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/save_template_ui.py:43
-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/dialogs/config/save_template_ui.py:44
-msgid "Available variables:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/social.py:34
-msgid "Downloading social metadata, please wait..."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:35
-msgid "Switch between library and device views"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:38
-msgid "Separator"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:51
-msgid "Choose library"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:201
-msgid "The main toolbar"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:202
-msgid "The main toolbar when a device is connected"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:203
-msgid "The context menu for the books in the calibre library"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:205
-msgid "The context menu for the books on the device"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:243
-msgid "Cannot add"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:244
-msgid "Cannot add the actions %s to this location"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:261
-msgid "Cannot remove"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar.py:262
-msgid "Cannot remove the actions %s from this location"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:97
-msgid "Customize the actions in:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:98
-msgid "A&vailable actions"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:99
-msgid "&Current actions"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:100
-msgid "Move selected action up"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:102
-msgid "Move selected action down"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:104
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:78
-msgid "Ctrl+S"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:105
-msgid "Add selected actions to toolbar"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:107
-msgid "Remove selected actions from toolbar"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/toolbar_ui.py:109
-msgid "Restore to &default"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:50
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:55
msgid "&Show this warning again"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/conversion_error_ui.py:42
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/conversion_error_ui.py:47
msgid "ERROR"
msgstr ""
@@ -6206,6 +5278,15 @@ msgstr ""
msgid "Location"
msgstr ""
+#:
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:69
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:889
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:31
+#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:588
+msgid "Date"
+msgstr ""
+
#:
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1064
@@ -6282,55 +5363,55 @@ msgstr ""
msgid "No metadata found, try adjusting the title and author or the ISBN key."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:85
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:90
msgid "Fetch metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:86
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:91
msgid "
calibre can find metadata for your books from two locations: Google Books and isbndb.com.
To use isbndb.com you must sign up for a free account and enter your access key below."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:87
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:92
msgid "&Access Key:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:88
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:93
msgid "Fetch"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:89
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:94
msgid "Matches"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:90
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:95
msgid "Select the book that most closely matches your copy from the list below"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:91
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:96
msgid "Download &social metadata (tags/rating/etc.) for the selected book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:92
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:97
msgid "Overwrite author and title with author and title of selected book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/job_view_ui.py:37
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/job_view_ui.py:42
msgid "Details of job"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:44
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:49
msgid "Active Jobs"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:45
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:50
msgid "&Stop selected job"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:46
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:51
msgid "Show job &details"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:47
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:52
msgid "Stop &all non device jobs"
msgstr ""
@@ -6342,80 +5423,80 @@ msgstr ""
msgid "Applying changes to %d books. This may take a while."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:160
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:165
msgid "Edit Meta information"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:162
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:167
msgid "A&utomatically set author sort"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:163
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:168
msgid "Author s&ort: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:164
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:367
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:169
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:372
msgid "Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:165
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:370
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:170
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:375
msgid "&Rating:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:166
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:167
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:371
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:372
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:171
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:172
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:376
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:377
msgid "Rating of this book. 0-5 stars"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:168
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:173
msgid "No change"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:169
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:373
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:174
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:378
msgid " stars"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:171
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:176
msgid "Add ta&gs: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:173
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:174
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:377
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:378
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:178
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:179
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:382
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:383
msgid "Open Tag Editor"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:175
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:180
msgid "&Remove tags:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:176
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:181
msgid "Comma separated list of tags to remove from the books. "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:177
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:182
msgid "Remove all"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:178
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:183
msgid "Check this box to remove all tags from the books."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:182
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:187
msgid "Remove &format:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:183
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:188
msgid "&Swap title and author"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:184
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:189
msgid ""
"Selected books will be automatically numbered,\n"
"in the order you selected them.\n"
@@ -6423,24 +5504,24 @@ msgid ""
"Book A will have series number 1 and Book B series number 2."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:189
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:194
msgid ""
"Remove stored conversion settings for the selected books.\n"
"\n"
"Future conversion of these books will use the default settings."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:192
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:197
msgid "Remove &stored conversion settings for the selected books"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:193
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:408
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:198
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:413
msgid "&Basic metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:194
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:409
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:199
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:414
msgid "&Custom metadata"
msgstr ""
@@ -6580,98 +5661,118 @@ msgstr ""
msgid "Could not open %s. Is it being used by another program?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:359
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:364
msgid "Edit Meta Information"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:360
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:365
msgid "Meta information"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:363
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:368
msgid "Swap the author and title"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:366
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:371
msgid "Author S&ort: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:368
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:373
msgid "Automatically create the author sort entry based on the current author entry"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:382
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:387
msgid "Remove unused series (Series that have no books)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:384
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:389
msgid "IS&BN:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:385
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:390
msgid "Publishe&d:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:388
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:393
msgid "dd MMM yyyy"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:389
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:394
msgid "&Date:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:390
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:395
msgid "&Comments"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:391
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:396
msgid "&Fetch metadata from server"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:392
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:397
msgid "Available Formats"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:393
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:398
msgid "Add a new format for this book to the database"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:395
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:400
msgid "Remove the selected formats for this book from the database."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:397
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:402
msgid "Set the cover for the book from the selected format"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:399
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:404
msgid "Update metadata from the metadata in the selected format"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:402
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:407
msgid "&Browse"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:403
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:408
msgid "Reset cover to default"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:405
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:410
msgid "Download &cover"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:406
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:411
msgid "Generate a default cover based on the title and author"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:407
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:412
msgid "&Generate cover"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:56
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:61
msgid "Password needed"
msgstr ""
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:63
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:217
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/server_ui.py:125
+#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:117
+msgid "&Username:"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:64
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:218
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/server_ui.py:126
+#: /home/kovid/work/calibre/src/calibre/gui2/wizard/send_email_ui.py:119
+msgid "&Password:"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:65
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:219
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/server_ui.py:130
+msgid "&Show password"
+msgstr ""
+
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress.py:59
msgid "Aborting..."
msgstr ""
@@ -6685,37 +5786,37 @@ msgid "The current saved search will be permanently deleted. Are you sure
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:83
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:88
msgid "Saved Search Editor"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:84
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:89
msgid "Saved Search: "
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:85
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:90
msgid "Select a saved search to edit"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:86
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:91
msgid "Delete this selected saved search"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:88
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:93
msgid "Enter a new saved search name."
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:89
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:94
msgid "Add the new saved search"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:91
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor_ui.py:96
msgid "Change the contents of the saved search"
msgstr ""
@@ -6744,7 +5845,7 @@ msgid "Last downloaded"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:220
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:192
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:197
msgid "Schedule news download"
msgstr ""
@@ -6764,111 +5865,111 @@ msgstr ""
msgid "Cannot download news as no internet connection is active"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:193
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:198
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:278
msgid "Recipes"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:194
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:199
msgid "Download all scheduled recipes at once"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:195
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:200
msgid "Download &all scheduled"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:196
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:201
msgid "blurb"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:197
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:202
msgid "&Schedule for download:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:198
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:208
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:203
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:213
msgid "Every "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:199
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:204
msgid "day"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:200
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:205
msgid "Monday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:201
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:206
msgid "Tuesday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:202
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:207
msgid "Wednesday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:203
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:208
msgid "Thursday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:204
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:209
msgid "Friday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:205
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:210
msgid "Saturday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:206
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:211
msgid "Sunday"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:207
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:212
msgid "at"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:209
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:214
msgid "Interval at which to download this recipe. A value of zero means that the recipe will be downloaded every hour."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:210
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:222
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:263
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:215
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:227
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:268
msgid " days"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:211
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:216
msgid "&Account"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:215
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:220
msgid "For the scheduling to work, you must leave calibre running."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:216
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:221
msgid "&Schedule"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:217
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:222
msgid "Add &title as tag"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:218
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:223
msgid "&Extra tags:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:219
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:224
msgid "&Advanced"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:220
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:225
msgid "&Download now"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:221
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:226
msgid "Delete downloaded news older than the specified number of days. Set to zero to disable."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:223
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:228
msgid "Delete downloaded news older than "
msgstr ""
@@ -6888,55 +5989,55 @@ msgstr ""
msgid "Negate"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:113
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:118
msgid "Advanced Search"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:114
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:119
msgid "Find entries that have..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:115
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:120
msgid "&All these words:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:116
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:121
msgid "This exact &phrase:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:117
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:122
msgid "&One or more of these words:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:118
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:123
msgid "But dont show entries that have..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:119
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:124
msgid "Any of these &unwanted words:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:120
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:125
msgid "What kind of match to use:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:121
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:126
msgid "Contains: the word or phrase matches anywhere in the metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:122
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:127
msgid "Equals: the word or phrase must match an entire metadata field"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:123
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:128
msgid "Regular expression: the expression must match anywhere in the metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:124
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:129
msgid " "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:125
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:130
msgid "See the User Manual for more help"
msgstr ""
@@ -6962,51 +6063,51 @@ msgstr ""
msgid "The current tag category will be permanently deleted. Are you sure?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:153
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:158
msgid "User Categories Editor"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:154
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:159
msgid "A&vailable items"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:155
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:160
msgid "Apply tags to current tag category"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:157
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:162
msgid "A&pplied items"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:158
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:163
msgid "Unapply (remove) tag from current tag category"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:160
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:165
msgid "Category name: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:161
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:166
msgid "Select a category to edit"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:162
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:167
msgid "Delete this selected tag category"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:164
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:169
msgid "Enter a new category name. Select the kind before adding it."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:165
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:170
msgid "Add the new category"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:167
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:172
msgid "Category filter: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:168
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories_ui.py:173
msgid "Select the content kind of the new category"
msgstr ""
@@ -7019,39 +6120,39 @@ msgstr ""
msgid "The following tags are used by one or more books. Are you certain you want to delete them?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:123
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:128
msgid "Tag Editor"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:124
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:129
msgid "A&vailable tags"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:125
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:130
msgid "Delete tag from database. This will unapply the tag from all books and then remove it from the database."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:127
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:132
msgid "Apply tag to current book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:129
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:134
msgid "A&pplied tags"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:130
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:135
msgid "Unapply (remove) tag from current book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:132
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:137
msgid "&Add tag:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:133
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:138
msgid "If the tag you want is not in the available list, you can add it here. Accepts a comma separated list of tags."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:134
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor_ui.py:139
msgid "Add tag to available tags and apply it to current book"
msgstr ""
@@ -7089,31 +6190,36 @@ msgstr ""
msgid "Are you certain you want to delete the following items?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:72
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:77
msgid "Category Editor"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:73
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:78
msgid "Items in use"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:74
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:79
msgid "Delete item from database. This will unapply the item from all books and then remove it from the database."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:76
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:81
msgid "Rename the item in every book where it is used."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/test_email_ui.py:51
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor_ui.py:83
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar_ui.py:106
+msgid "Ctrl+S"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/test_email_ui.py:56
msgid "Test email settings"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/test_email_ui.py:52
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/test_email_ui.py:57
msgid "Send test mail from %s to:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/test_email_ui.py:53
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/test_email_ui.py:58
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:115
msgid "&Test"
msgstr ""
@@ -7132,7 +6238,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:150
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:161
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:255
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:260
msgid "Switch to Advanced mode"
msgstr ""
@@ -7197,35 +6303,35 @@ msgstr ""
msgid "Choose a recipe file"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:248
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:253
msgid "Add custom news source"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:249
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:254
msgid "Available user recipes"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:250
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:255
msgid "Add/Update &recipe"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:251
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:256
msgid "&Remove recipe"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:252
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:257
msgid "&Share recipe"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:253
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:258
msgid "Customize &builtin recipe"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:254
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:259
msgid "&Load recipe from file"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:256
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:261
msgid ""
"