diff --git a/resources/images/connect_share.svg b/resources/images/connect_share.svg new file mode 100644 index 0000000000..ab582ddc57 --- /dev/null +++ b/resources/images/connect_share.svg @@ -0,0 +1,5123 @@ + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/images/dictionary.png b/resources/images/dictionary.png deleted file mode 100644 index e9bd55d918..0000000000 Binary files a/resources/images/dictionary.png and /dev/null differ diff --git a/resources/images/dictionary.svg b/resources/images/dictionary.svg new file mode 100644 index 0000000000..37b17baf48 --- /dev/null +++ b/resources/images/dictionary.svg @@ -0,0 +1,1009 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/images/user_profile.svg b/resources/images/user_profile.svg index 0aecc0c1f7..3b2f36131a 100644 --- a/resources/images/user_profile.svg +++ b/resources/images/user_profile.svg @@ -2,7 +2,7 @@ + sodipodi:docbase="/home/pinheiro/artwork/Oxygen/theme/svg/actions" + sodipodi:docname="user_female.svg"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + inkscape:window-width="1106" + inkscape:window-height="958" + inkscape:window-x="128" + inkscape:window-y="215"> + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="metadata1312"> image/svg+xml + + + + Oxygen team + + + + + + + + + + + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + + + style="opacity:0.38139535;fill:url(#radialGradient3297);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1" + id="path3289" + sodipodi:cx="63.912209" + sodipodi:cy="115.70919" + sodipodi:rx="63.912209" + sodipodi:ry="12.641975" + d="M 127.82442 115.70919 A 63.912209 12.641975 0 1 1 0,115.70919 A 63.912209 12.641975 0 1 1 127.82442 115.70919 z" + transform="matrix(1,0,0,0.416667,0.266436,74.25798)" /> + style="fill:black;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 64.126842,1.3826379 C 58.426392,1.4554645 52.905637,4.1403867 48.381995,10.414566 C 35.911196,13.756106 32.695587,31.476866 31.599697,43.796082 C 30.207379,59.447533 38.215631,69.284604 49.114313,73.516007 C 48.955505,75.292398 48.560056,76.805464 48.015836,77.726838 C 45.968001,81.19384 41.318471,84.201393 33.277926,86.484146 C 24.307525,89.030883 17.192434,91.505674 12.040691,96.0348 C 7.4798115,100.04448 4.5344266,104.68101 4.5344266,110.62014 C 4.5344266,126.036 123.87182,126.85211 123.87182,110.62014 C 123.87183,104.68101 120.92644,100.04447 116.36556,96.0348 C 111.27103,91.555971 104.15639,88.925208 95.128324,86.362093 C 87.028227,84.062439 82.381647,81.149675 80.359901,77.726838 C 79.684606,76.58356 79.264762,74.560445 79.200397,72.203936 C 89.11651,67.571946 96.962124,58.62877 98.118624,45.443799 C 99.954507,24.513404 81.228191,1.1641579 64.126842,1.3826379 z " + id="path2375" /> - - - - - + id="path2878" + d="M 64.126842,1.3826379 C 58.426392,1.4554645 52.905637,4.1403867 48.381995,10.414566 C 35.911196,13.756106 32.695587,31.476866 31.599697,43.796082 C 30.207379,59.447533 38.215631,69.284604 49.114313,73.516007 C 48.955505,75.292398 48.560056,76.805464 48.015836,77.726838 C 45.968001,81.19384 41.318471,84.201393 33.277926,86.484146 C 24.307525,89.030883 17.192434,91.505674 12.040691,96.0348 C 7.4798115,100.04448 4.5344266,104.68101 4.5344266,110.62014 C 4.5344266,126.036 123.87182,126.85211 123.87182,110.62014 C 123.87183,104.68101 120.92644,100.04447 116.36556,96.0348 C 111.27103,91.555971 104.15639,88.925208 95.128324,86.362093 C 87.028227,84.062439 82.381647,81.149675 80.359901,77.726838 C 79.684606,76.58356 79.264762,74.560445 79.200397,72.203936 C 89.11651,67.571946 96.962124,58.62877 98.118624,45.443799 C 99.954507,24.513404 81.228191,1.1641579 64.126842,1.3826379 z " + style="fill:black;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="fill:url(#linearGradient2898);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.2073171" + d="M 63.805682,2.3189945 C 60.204653,2.3650007 56.68272,3.4814485 53.43117,5.8585338 C 56.378477,3.9906882 61.133543,3.7479685 64.326992,4.0398775 C 79.377077,5.4155836 98.565383,26.21259 96.7295,47.142988 C 95.820607,57.505059 90.782821,65.24448 83.8529,70.333073 C 91.331974,65.269474 96.842277,57.270013 97.797464,46.380156 C 99.633352,25.449758 80.907031,2.1005146 63.805682,2.3189945 z " + id="path2882" + sodipodi:nodetypes="ccsscsc" /> + style="fill:url(#linearGradient2911);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 79.147382,75.901301 C 79.100289,75.923554 79.049359,75.937341 79.002158,75.959388 C 79.063429,78.202509 79.46307,80.128263 80.10587,81.216537 C 82.030334,84.47468 86.453333,87.247287 94.163669,89.436284 C 102.75732,91.876067 109.52963,94.380244 114.37901,98.643562 C 118.37935,102.16043 121.06728,106.18674 121.466,111.22007 C 121.49137,111.05961 121.5241,110.89043 121.5241,110.7263 C 121.5241,105.07295 118.72043,100.65951 114.37901,96.842768 C 109.52963,92.579463 102.75732,90.075276 94.163669,87.635494 C 86.453333,85.446506 82.030334,82.673889 80.10587,79.415746 C 79.636815,78.621639 79.320492,77.385183 79.147382,75.901301 z " + id="path2900" + sodipodi:nodetypes="ccssscssssc" /> + sodipodi:nodetypes="ccssscssssc" + id="path2913" + d="M 50.410374,75.901301 C 50.457467,75.923554 50.508398,75.937341 50.555598,75.959388 C 50.494327,78.202509 50.094687,80.128263 49.451887,81.216537 C 47.527422,84.47468 43.104424,87.247287 35.394087,89.436284 C 26.800432,91.876067 20.028126,94.380244 15.178743,98.643562 C 11.178409,102.16043 8.4904782,106.18674 8.0917552,111.22007 C 8.0663877,111.05961 8.033658,110.89043 8.033658,110.7263 C 8.033658,105.07295 10.837325,100.65951 15.178743,96.842768 C 20.028126,92.579463 26.800432,90.075276 35.394087,87.635494 C 43.104424,85.446506 47.527422,82.673889 49.451887,79.415746 C 49.920942,78.621639 50.237264,77.385183 50.410374,75.901301 z " + style="fill:url(#linearGradient2915);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + style="opacity:0.19262294;fill:url(#linearGradient2934);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 64.126842,1.3826379 C 58.426392,1.4554645 52.905637,4.1403867 48.381995,10.414566 C 35.911196,13.756106 32.695587,31.476866 31.599697,43.796082 C 30.207379,59.447533 38.215631,69.284604 49.114313,73.516007 C 48.955505,75.292398 48.560056,76.805464 48.015836,77.726838 C 45.968001,81.19384 41.318471,84.201393 33.277926,86.484146 C 24.307525,89.030883 17.192434,91.505674 12.040691,96.0348 C 10.934256,97.007517 9.9476914,98.029977 9.0503905,99.086127 C 43.790302,112.20602 86.237691,93.86764 120.45434,100.45922 C 119.31869,98.895255 117.94232,97.420999 116.36556,96.0348 C 111.27103,91.555971 104.15639,88.925208 95.128324,86.362093 C 87.028227,84.062439 82.381647,81.149675 80.359901,77.726838 C 79.684606,76.58356 79.264762,74.560445 79.200397,72.203936 C 89.11651,67.571946 96.962124,58.62877 98.118624,45.443799 C 99.954507,24.513404 81.228191,1.1641579 64.126842,1.3826379 z " + id="path2923" + sodipodi:nodetypes="ccscsssccssscsc" /> + style="opacity:0.147541;fill:url(#linearGradient2942);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 64.126842,1.3826379 C 58.426392,1.4554645 52.905637,4.1403867 48.381995,10.414566 C 35.911196,13.756106 32.695587,31.476866 31.599697,43.796082 C 30.590647,55.139108 34.51846,63.410713 40.906244,68.725424 C 46.499431,43.086176 60.253253,23.183408 81.916078,8.8889022 C 76.436168,4.2058259 70.185402,1.3052361 64.126842,1.3826379 z M 91.588784,20.392405 C 69.413597,38.642858 59.93157,63.059075 62.204506,99.635366 C 82.545047,99.174142 102.74074,98.667446 120.45434,100.45922 C 119.31869,98.895255 117.94232,97.420999 116.36556,96.0348 C 111.27103,91.555971 104.15639,88.925208 95.128324,86.362093 C 87.028227,84.062439 82.381647,81.149675 80.359901,77.726838 C 79.684606,76.58356 79.264762,74.560445 79.200397,72.203936 C 89.11651,67.571946 96.962124,58.62877 98.118624,45.443799 C 98.867542,36.905593 96.177208,27.971578 91.588784,20.392405 z " + id="path2936" + sodipodi:nodetypes="ccsccccccssscsc" /> - - + style="fill:url(#radialGradient2824);fill-opacity:1.0;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:0.41803279" + d="M 64.126842,1.3826379 C 58.426392,1.4554645 52.905637,4.1403867 48.381995,10.414566 C 35.911196,13.756106 32.695587,31.476866 31.599697,43.796082 C 30.207379,59.447533 38.215631,69.284604 49.114313,73.516007 C 48.955505,75.292398 48.560056,76.805464 48.015836,77.726838 C 45.968001,81.19384 41.318471,84.201393 33.277926,86.484146 C 24.307525,89.030883 17.192434,91.505674 12.040691,96.0348 C 7.4798115,100.04448 4.5344266,104.68101 4.5344266,110.62014 C 4.5344266,126.036 123.87182,126.85211 123.87182,110.62014 C 123.87183,104.68101 120.92644,100.04447 116.36556,96.0348 C 111.27103,91.555971 104.15639,88.925208 95.128324,86.362093 C 87.028227,84.062439 82.381647,81.149675 80.359901,77.726838 C 79.684606,76.58356 79.264762,74.560445 79.200397,72.203936 C 89.11651,67.571946 96.962124,58.62877 98.118624,45.443799 C 99.954507,24.513404 81.228191,1.1641579 64.126842,1.3826379 z " + id="path1928" /> diff --git a/resources/recipes/npr.recipe b/resources/recipes/npr.recipe index 167c2125c7..8a4d2f9873 100644 --- a/resources/recipes/npr.recipe +++ b/resources/recipes/npr.recipe @@ -6,6 +6,7 @@ class AdvancedUserRecipe1257302745(BasicNewsRecipe): language = 'en' __author__ = 'onyxrev' max_articles_per_feed = 100 + no_stylesheets = True remove_tags_before = {'class':'storytitle'} remove_tags_after = dict(name='div', attrs={'id':'storytext' }) diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index e45334777e..7a53abb067 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -295,11 +295,10 @@ class MetaInformation(object): if val is not None: setattr(self, attr, val) - if mi.tags: - if replace_metadata: - self.tags = mi.tags - else: - self.tags += mi.tags + if replace_metadata: + self.tags = mi.tags + elif mi.tags: + self.tags += mi.tags self.tags = list(set(self.tags)) if mi.author_sort_map: @@ -313,14 +312,17 @@ class MetaInformation(object): if len(other_cover) > len(self_cover): self.cover_data = mi.cover_data - my_comments = getattr(self, 'comments', '') - other_comments = getattr(mi, 'comments', '') - if not my_comments: - my_comments = '' - if not other_comments: - other_comments = '' - if len(other_comments.strip()) > len(my_comments.strip()): - self.comments = other_comments + if replace_metadata: + self.comments = getattr(mi, 'comments', '') + else: + my_comments = getattr(self, 'comments', '') + other_comments = getattr(mi, 'comments', '') + if not my_comments: + my_comments = '' + if not other_comments: + other_comments = '' + if len(other_comments.strip()) > len(my_comments.strip()): + self.comments = other_comments other_lang = getattr(mi, 'language', None) if other_lang and other_lang.lower() != 'und': diff --git a/src/calibre/gui2/actions.py b/src/calibre/gui2/actions.py index 9522083b98..a49ff76e67 100644 --- a/src/calibre/gui2/actions.py +++ b/src/calibre/gui2/actions.py @@ -578,9 +578,7 @@ class DeleteAction(object): # {{{ if row is not None: ci = view.model().index(row, 0) if ci.isValid(): - view.setCurrentIndex(ci) - sm = view.selectionModel() - sm.select(ci, sm.Select) + view.set_current_row(row) else: if not confirm('

'+_('The selected books will be ' 'permanently deleted ' diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index c919547956..cdbe31de65 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -395,8 +395,6 @@ class DeviceAction(QAction): # {{{ class DeviceMenu(QMenu): # {{{ fetch_annotations = pyqtSignal() - connect_to_folder = pyqtSignal() - connect_to_itunes = pyqtSignal() disconnect_mounted_device = pyqtSignal() def __init__(self, parent=None): @@ -408,26 +406,6 @@ class DeviceMenu(QMenu): # {{{ self.set_default_menu = QMenu(_('Set default send to device action')) self.set_default_menu.setIcon(QIcon(I('config.svg'))) - opts = email_config().parse() - default_account = None - if opts.accounts: - self.email_to_menu = self.addMenu(_('Email to')+'...') - keys = sorted(opts.accounts.keys()) - for account in keys: - formats, auto, default = opts.accounts[account] - dest = 'mail:'+account+';'+formats - if default: - default_account = (dest, False, False, I('mail.svg'), - _('Email to')+' '+account) - action1 = DeviceAction(dest, False, False, I('mail.svg'), - _('Email to')+' '+account) - action2 = DeviceAction(dest, True, False, I('mail.svg'), - _('Email to')+' '+account+ _(' and delete from library')) - map(self.email_to_menu.addAction, (action1, action2)) - map(self._memory.append, (action1, action2)) - self.email_to_menu.addSeparator() - action1.a_s.connect(self.action_triggered) - action2.a_s.connect(self.action_triggered) basic_actions = [ ('main:', False, False, I('reader.svg'), @@ -457,13 +435,6 @@ class DeviceMenu(QMenu): # {{{ ] - if default_account is not None: - for x in (basic_actions, delete_actions): - ac = list(default_account) - if x is delete_actions: - ac[1] = True - x.insert(1, tuple(ac)) - for menu in (self, self.set_default_menu): for actions, desc in ( (basic_actions, ''), @@ -502,21 +473,7 @@ class DeviceMenu(QMenu): # {{{ config['default_send_to_device_action'] = repr(action) self.group.triggered.connect(self.change_default_action) - if opts.accounts: - self.addSeparator() - self.addMenu(self.email_to_menu) - self.addSeparator() - mitem = self.addAction(QIcon(I('document_open.svg')), _('Connect to folder')) - mitem.setEnabled(True) - mitem.triggered.connect(lambda x : self.connect_to_folder.emit()) - self.connect_to_folder_action = mitem - - mitem = self.addAction(QIcon(I('devices/itunes.png')), - _('Connect to iTunes')) - mitem.setEnabled(True) - mitem.triggered.connect(lambda x : self.connect_to_itunes.emit()) - self.connect_to_itunes_action = mitem mitem = self.addAction(QIcon(I('eject.svg')), _('Eject device')) mitem.setEnabled(False) @@ -638,6 +595,8 @@ class DeviceMixin(object): # {{{ self.device_error_dialog = error_dialog(self, _('Error'), _('Error communicating with device'), ' ') self.device_error_dialog.setModal(Qt.NonModal) + self.share_conn_menu.connect_to_folder.connect(self.connect_to_folder) + self.share_conn_menu.connect_to_itunes.connect(self.connect_to_itunes) self.emailer = Emailer() self.emailer.start() self.device_manager = DeviceManager(Dispatcher(self.device_detected), @@ -675,21 +634,20 @@ class DeviceMixin(object): # {{{ def create_device_menu(self): self._sync_menu = DeviceMenu(self) + self.share_conn_menu.build_email_entries(self._sync_menu) self.action_sync.setMenu(self._sync_menu) self.connect(self._sync_menu, SIGNAL('sync(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.dispatch_sync_event) self._sync_menu.fetch_annotations.connect(self.fetch_annotations) - self._sync_menu.connect_to_folder.connect(self.connect_to_folder) - self._sync_menu.connect_to_itunes.connect(self.connect_to_itunes) self._sync_menu.disconnect_mounted_device.connect(self.disconnect_mounted_device) if self.device_connected: - self._sync_menu.connect_to_folder_action.setEnabled(False) - self._sync_menu.connect_to_itunes_action.setEnabled(False) + self.share_conn_menu.connect_to_folder_action.setEnabled(False) + self.share_conn_menu.connect_to_itunes_action.setEnabled(False) self._sync_menu.disconnect_mounted_device_action.setEnabled(True) else: - self._sync_menu.connect_to_folder_action.setEnabled(True) - self._sync_menu.connect_to_itunes_action.setEnabled(True) + self.share_conn_menu.connect_to_folder_action.setEnabled(True) + self.share_conn_menu.connect_to_itunes_action.setEnabled(True) self._sync_menu.disconnect_mounted_device_action.setEnabled(False) def device_job_exception(self, job): @@ -726,16 +684,16 @@ class DeviceMixin(object): # {{{ def set_device_menu_items_state(self, connected): if connected: - self._sync_menu.connect_to_folder_action.setEnabled(False) - self._sync_menu.connect_to_itunes_action.setEnabled(False) + self.share_conn_menu.connect_to_folder_action.setEnabled(False) + self.share_conn_menu.connect_to_itunes_action.setEnabled(False) self._sync_menu.disconnect_mounted_device_action.setEnabled(True) self._sync_menu.enable_device_actions(True, self.device_manager.device.card_prefix(), self.device_manager.device) self.eject_action.setEnabled(True) else: - self._sync_menu.connect_to_folder_action.setEnabled(True) - self._sync_menu.connect_to_itunes_action.setEnabled(True) + self.share_conn_menu.connect_to_folder_action.setEnabled(True) + self.share_conn_menu.connect_to_itunes_action.setEnabled(True) self._sync_menu.disconnect_mounted_device_action.setEnabled(False) self._sync_menu.enable_device_actions(False) self.eject_action.setEnabled(False) @@ -983,6 +941,8 @@ class DeviceMixin(object): # {{{ else: self.status_bar.show_message(_('Sent by email:') + ', '.join(good), 5000) + if remove: + self.library_view.model().delete_books_by_id(remove) def cover_to_thumbnail(self, data): p = QPixmap() diff --git a/src/calibre/gui2/dialogs/choose_library.py b/src/calibre/gui2/dialogs/choose_library.py index 03bd303112..f53f617448 100644 --- a/src/calibre/gui2/dialogs/choose_library.py +++ b/src/calibre/gui2/dialogs/choose_library.py @@ -10,7 +10,7 @@ import os from PyQt4.Qt import QDialog from calibre.gui2.dialogs.choose_library_ui import Ui_Dialog -from calibre.gui2 import error_dialog, choose_dir, warning_dialog +from calibre.gui2 import error_dialog, choose_dir from calibre.constants import filesystem_encoding from calibre import isbytestring, patheq from calibre.utils.config import prefs @@ -62,12 +62,6 @@ class ChooseLibrary(QDialog, Ui_Dialog): return True def perform_action(self, ac, loc): - if ac in ('new', 'existing'): - warning_dialog(self.parent(), _('Custom columns'), - _('If you use custom columns and they differ between ' - 'libraries, you will have various problems. Best ' - 'to ensure you have the same custom columns in each ' - 'library.'), show=True) if ac in ('new', 'existing'): prefs['library_path'] = loc self.callback(loc) diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py index 84d55c8fb6..5dcc4feb1a 100644 --- a/src/calibre/gui2/dialogs/config/__init__.py +++ b/src/calibre/gui2/dialogs/config/__init__.py @@ -195,22 +195,32 @@ class PluginModel(QAbstractItemModel): class CategoryModel(QStringListModel): + CATEGORIES = [ + ('general', _('General'), 'dialog_information.svg'), + ('interface', _('Interface'), 'lookfeel.svg'), + ('conversion', _('Conversion'), 'convert.svg'), + ('email', _('Email\nDelivery'), 'mail.svg'), + ('add/save', _('Add/Save'), 'save.svg'), + ('advanced', _('Advanced'), 'view.svg'), + ('server', _('Content\nServer'), 'network-server.svg'), + ('plugins', _('Plugins'), 'plugins.svg'), + ] + def __init__(self, *args): QStringListModel.__init__(self, *args) - self.setStringList([_('General'), _('Interface'), _('Conversion'), - _('Email\nDelivery'), _('Add/Save'), - _('Advanced'), _('Content\nServer'), _('Plugins')]) - self.icons = list(map(QVariant, map(QIcon, - [I('dialog_information.svg'), I('lookfeel.svg'), - I('convert.svg'), - I('mail.svg'), I('save.svg'), I('view.svg'), - I('network-server.svg'), I('plugins.svg')]))) + self.setStringList([x[1] for x in self.CATEGORIES]) def data(self, index, role): if role == Qt.DecorationRole: - return self.icons[index.row()] + 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): @@ -332,7 +342,8 @@ 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): + def __init__(self, parent, library_view, server=None, + initial_category='general'): ResizableDialog.__init__(self, parent) self._category_model = CategoryModel() @@ -461,7 +472,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): self.button_osx_symlinks.setVisible(isosx) self.separate_cover_flow.setChecked(config['separate_cover_flow']) self.setup_email_page() - self.category_view.setCurrentIndex(self.category_view.model().index(0)) self.delete_news.setEnabled(bool(self.sync_news.isChecked())) self.connect(self.sync_news, SIGNAL('toggled(bool)'), self.delete_news.setEnabled) @@ -488,6 +498,22 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): self.opt_gui_layout.setCurrentIndex(li) self.opt_disable_animations.setChecked(config['disable_animations']) self.opt_show_donate_button.setChecked(config['show_donate_button']) + 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.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category)) def check_port_value(self, *args): port = self.port.value() @@ -857,6 +883,10 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): config['disable_animations'] = bool(self.opt_disable_animations.isChecked()) config['show_donate_button'] = bool(self.opt_show_donate_button.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: @@ -942,6 +972,5 @@ if __name__ == '__main__': from PyQt4.Qt import QApplication app = QApplication([]) d=ConfigDialog(None, LibraryDatabase2('/tmp')) - d.category_view.setCurrentIndex(d.category_view.model().index(0)) d.show() app.exec_() diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui index 5d6bff2467..df19aa2a26 100644 --- a/src/calibre/gui2/dialogs/config/config.ui +++ b/src/calibre/gui2/dialogs/config/config.ui @@ -346,21 +346,21 @@ - + Automatically send downloaded &news to ebook reader - + &Delete news from library when it is automatically sent to reader - + @@ -377,7 +377,7 @@ - + @@ -580,6 +580,41 @@ + + + + &Toolbar + + + + + + + + + &Icon size: + + + opt_toolbar_icon_size + + + + + + + + + + Show &text under icons: + + + opt_toolbar_text + + + + + + diff --git a/src/calibre/gui2/dialogs/saved_search_editor.py b/src/calibre/gui2/dialogs/saved_search_editor.py index 6a8b790625..3f9f7ad437 100644 --- a/src/calibre/gui2/dialogs/saved_search_editor.py +++ b/src/calibre/gui2/dialogs/saved_search_editor.py @@ -25,8 +25,8 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): self.current_search_name = None self.searches = {} self.searches_to_delete = [] - for name in saved_searches.names(): - self.searches[name] = saved_searches.lookup(name) + for name in saved_searches().names(): + self.searches[name] = saved_searches().lookup(name) self.populate_search_list() if initial_search is not None and initial_search in self.searches: @@ -78,7 +78,7 @@ class SavedSearchEditor(QDialog, Ui_SavedSearchEditor): if self.current_search_name: self.searches[self.current_search_name] = unicode(self.search_text.toPlainText()) for name in self.searches_to_delete: - saved_searches.delete(name) + saved_searches().delete(name) for name in self.searches: - saved_searches.add(name, self.searches[name]) + saved_searches().add(name, self.searches[name]) QDialog.accept(self) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index 7b4af2d162..3dbf7ffffd 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -62,6 +62,7 @@ class SchedulerDialog(QDialog, Ui_Dialog): self.search_done) self.disconnect(self.recipe_model, SIGNAL('searched(PyQt_PyObject)'), self.search.search_done) + self.search.search.disconnect() self.recipe_model = None def search_done(self, *args): diff --git a/src/calibre/gui2/dialogs/tag_categories.py b/src/calibre/gui2/dialogs/tag_categories.py index b7d64226ab..0a54696801 100644 --- a/src/calibre/gui2/dialogs/tag_categories.py +++ b/src/calibre/gui2/dialogs/tag_categories.py @@ -7,7 +7,6 @@ from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtGui import QDialog, QIcon, QListWidgetItem from calibre.gui2.dialogs.tag_categories_ui import Ui_TagCategories -from calibre.utils.config import prefs from calibre.gui2.dialogs.confirm_delete import confirm from calibre.constants import islinux @@ -63,7 +62,7 @@ class TagCategories(QDialog, Ui_TagCategories): self.all_items.append(t) self.all_items_dict[label+':'+n] = t - self.categories = dict.copy(prefs['user_categories']) + self.categories = dict.copy(db.prefs.get('user_categories', {})) if self.categories is None: self.categories = {} for cat in self.categories: @@ -182,7 +181,7 @@ class TagCategories(QDialog, Ui_TagCategories): def accept(self): self.save_category() - prefs['user_categories'] = self.categories + self.db.prefs['user_categories'] = self.categories QDialog.accept(self) def save_category(self): diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 254d2c3d00..a3ae5b77aa 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -59,6 +59,7 @@ class LibraryViewMixin(object): # {{{ self.action_open_containing_folder, self.action_show_book_details, self.action_del, + self.action_conn_share, add_to_library = None, edit_device_collections=None, similar_menu=similar_menu) @@ -67,21 +68,24 @@ class LibraryViewMixin(object): # {{{ edit_device_collections = (_('Manage collections'), partial(self.edit_device_collections, oncard=None)) self.memory_view.set_context_menu(None, None, None, - self.action_view, self.action_save, None, None, self.action_del, + self.action_view, self.action_save, None, None, + self.action_del, None, add_to_library=add_to_library, edit_device_collections=edit_device_collections) edit_device_collections = (_('Manage collections'), partial(self.edit_device_collections, oncard='carda')) self.card_a_view.set_context_menu(None, None, None, - self.action_view, self.action_save, None, None, self.action_del, + self.action_view, self.action_save, None, None, + self.action_del, None, add_to_library=add_to_library, edit_device_collections=edit_device_collections) edit_device_collections = (_('Manage collections'), partial(self.edit_device_collections, oncard='cardb')) self.card_b_view.set_context_menu(None, None, None, - self.action_view, self.action_save, None, None, self.action_del, + self.action_view, self.action_save, None, None, + self.action_del, None, add_to_library=add_to_library, edit_device_collections=edit_device_collections) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 8604587649..012a9b5ce3 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -16,14 +16,14 @@ from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, \ from calibre.constants import __appname__, isosx from calibre.gui2.search_box import SearchBox2, SavedSearchBox from calibre.gui2.throbber import ThrobbingButton -from calibre.gui2 import config, open_url +from calibre.gui2 import config, open_url, gprefs from calibre.gui2.widgets import ComboBoxWithHelp from calibre import human_readable from calibre.utils.config import prefs from calibre.ebooks import BOOK_EXTENSIONS from calibre.gui2.dialogs.scheduler import Scheduler +from calibre.utils.smtp import config as email_config -ICON_SIZE = 48 class SaveMenu(QMenu): # {{{ @@ -228,12 +228,11 @@ class ToolBar(QToolBar): # {{{ self.setFloatable(False) self.setOrientation(Qt.Horizontal) self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea) - self.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) - self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.setStyleSheet('QToolButton:checked { font-weight: bold }') + self.donate = donate + self.apply_settings() self.all_actions = actions - self.donate = donate self.location_manager = location_manager self.location_manager.locations_changed.connect(self.build_bar) self.d_widget = QWidget() @@ -242,6 +241,17 @@ class ToolBar(QToolBar): # {{{ donate.setAutoRaise(True) donate.setCursor(Qt.PointingHandCursor) self.build_bar() + self.preferred_width = self.sizeHint().width() + + def apply_settings(self): + sz = gprefs.get('toolbar_icon_size', 'medium') + sz = {'small':24, 'medium':48, 'large':64}[sz] + self.setIconSize(QSize(sz, sz)) + style = Qt.ToolButtonTextUnderIcon + if gprefs.get('toolbar_text', 'auto') == 'never': + style = Qt.ToolButtonIconOnly + self.setToolButtonStyle(style) + self.donate.set_normal_icon_size(sz, sz) def contextMenuEvent(self, *args): pass @@ -262,7 +272,9 @@ class ToolBar(QToolBar): # {{{ ch.setCursor(Qt.PointingHandCursor) ch.setAutoRaise(True) if ac.menu() is not None: - ch.setPopupMode(ch.MenuButtonPopup) + name = getattr(ac, 'action_name', None) + ch.setPopupMode(ch.InstantPopup if name == 'conn_share' + else ch.MenuButtonPopup) for x in actions: self.addAction(x) @@ -292,11 +304,16 @@ class ToolBar(QToolBar): # {{{ a.setText(text) def resizeEvent(self, ev): - style = Qt.ToolButtonTextUnderIcon - if self.size().width() < 1260: - style = Qt.ToolButtonIconOnly - self.setToolButtonStyle(style) QToolBar.resizeEvent(self, ev) + style = Qt.ToolButtonTextUnderIcon + p = gprefs.get('toolbar_text', 'auto') + if p == 'never': + style = Qt.ToolButtonIconOnly + + if p == 'auto' and self.preferred_width > self.width()+35: + style = Qt.ToolButtonIconOnly + + self.setToolButtonStyle(style) def database_changed(self, db): pass @@ -306,6 +323,62 @@ class ToolBar(QToolBar): # {{{ class Action(QAction): pass +class ShareConnMenu(QMenu): # {{{ + + connect_to_folder = pyqtSignal() + connect_to_itunes = pyqtSignal() + config_email = pyqtSignal() + + def __init__(self, parent=None): + QMenu.__init__(self, parent) + mitem = self.addAction(QIcon(I('devices/folder.svg')), _('Connect to folder')) + mitem.setEnabled(True) + mitem.triggered.connect(lambda x : self.connect_to_folder.emit()) + self.connect_to_folder_action = mitem + + mitem = self.addAction(QIcon(I('devices/itunes.png')), + _('Connect to iTunes')) + mitem.setEnabled(True) + mitem.triggered.connect(lambda x : self.connect_to_itunes.emit()) + self.connect_to_itunes_action = mitem + self.addSeparator() + self.email_actions = [] + + def build_email_entries(self, sync_menu): + from calibre.gui2.device import DeviceAction + for ac in self.email_actions: + self.removeAction(ac) + self.email_actions = [] + opts = email_config().parse() + if opts.accounts: + self.email_to_menu = QMenu(_('Email to')+'...', self) + keys = sorted(opts.accounts.keys()) + for account in keys: + formats, auto, default = opts.accounts[account] + dest = 'mail:'+account+';'+formats + action1 = DeviceAction(dest, False, False, I('mail.svg'), + _('Email to')+' '+account) + action2 = DeviceAction(dest, True, False, I('mail.svg'), + _('Email to')+' '+account+ _(' and delete from library')) + map(self.email_to_menu.addAction, (action1, action2)) + if default: + map(self.addAction, (action1, action2)) + map(self.email_actions.append, (action1, action2)) + self.email_to_menu.addSeparator() + action1.a_s.connect(sync_menu.action_triggered) + action2.a_s.connect(sync_menu.action_triggered) + ac = self.addMenu(self.email_to_menu) + self.email_actions.append(ac) + else: + ac = self.addAction(_('Setup email based sharing of books')) + self.email_actions.append(ac) + ac.triggered.connect(self.setup_email) + + def setup_email(self, *args): + self.config_email.emit() + +# }}} + class MainWindowMixin(object): def __init__(self, db): @@ -321,7 +394,6 @@ class MainWindowMixin(object): self.centralwidget.setLayout(self._central_widget_layout) self.resize(1012, 740) self.donate_button = ThrobbingButton(self.centralwidget) - self.donate_button.set_normal_icon_size(ICON_SIZE, ICON_SIZE) self.location_manager = LocationManager(self) self.init_scheduler(db) @@ -341,7 +413,6 @@ class MainWindowMixin(object): self.scheduler.start_recipe_fetch.connect( self.download_scheduled_recipe, type=Qt.QueuedConnection) - def read_toolbar_settings(self): pass @@ -372,18 +443,19 @@ class MainWindowMixin(object): setattr(self, 'action_'+name, action) all_actions.append(action) - ac(0, 7, 0, 'add', _('Add books'), 'add_book.svg', _('A')) + ac(0, 0, 0, 'add', _('Add books'), 'add_book.svg', _('A')) ac(1, 1, 0, 'edit', _('Edit metadata'), 'edit_input.svg', _('E')) ac(2, 2, 3, 'convert', _('Convert books'), 'convert.svg', _('C')) ac(3, 3, 0, 'view', _('View'), 'view.svg', _('V')) - ac(4, 4, 3, 'choose_library', _('%d books')%0, 'lt.png', + ac(-1, 4, 0, 'sync', _('Send to device'), 'sync.svg') + ac(5, 5, 3, 'choose_library', _('%d books')%0, 'lt.png', tooltip=_('Choose calibre library to work with')) - ac(5, 5, 3, 'news', _('Fetch news'), 'news.svg', _('F')) - ac(6, 6, 0, 'save', _('Save to disk'), 'save.svg', _('S')) - ac(7, 0, 0, 'sync', _('Send to device'), 'sync.svg') - ac(8, 8, 3, 'del', _('Remove books'), 'trash.svg', _('Del')) - ac(9, 9, 3, 'help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual")) - ac(10, 10, 0, 'preferences', _('Preferences'), 'config.svg', _('Ctrl+P')) + ac(6, 6, 3, 'news', _('Fetch news'), 'news.svg', _('F')) + ac(7, 7, 0, 'save', _('Save to disk'), 'save.svg', _('S')) + ac(8, 8, 0, 'conn_share', _('Connect/share'), 'connect_share.svg') + ac(9, 9, 3, 'del', _('Remove books'), 'trash.svg', _('Del')) + ac(10, 10, 3, 'help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual")) + ac(11, 11, 0, 'preferences', _('Preferences'), 'config.svg', _('Ctrl+P')) ac(-1, -1, 0, 'merge', _('Merge book records'), 'merge_books.svg', _('M')) ac(-1, -1, 0, 'open_containing_folder', _('Open containing folder'), @@ -402,6 +474,10 @@ class MainWindowMixin(object): self.action_news.setMenu(self.scheduler.news_menu) self.action_news.triggered.connect( self.scheduler.show_dialog) + self.share_conn_menu = ShareConnMenu(self) + self.share_conn_menu.config_email.connect(partial(self.do_config, + initial_category='email')) + self.action_conn_share.setMenu(self.share_conn_menu) self.action_help.triggered.connect(self.show_help) md = QMenu() @@ -528,6 +604,7 @@ class MainWindowMixin(object): for x in (self.preferences_action, self.action_preferences): x.triggered.connect(self.do_config) + return all_actions # }}} diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index c6c32f86f7..870157c81a 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -214,13 +214,17 @@ class BooksView(QTableView): # {{{ state['column_sizes'][name] = h.sectionSize(i) return state + def write_state(self, state): + db = getattr(self.model(), 'db', None) + name = unicode(self.objectName()) + if name and db is not None: + db.prefs.set(name + ' books view state', state) + def save_state(self): # Only save if we have been initialized (set_database called) if len(self.column_map) > 0 and self.was_restored: state = self.get_state() - name = unicode(self.objectName()) - if name: - gprefs.set(name + ' books view state', state) + self.write_state(state) def cleanup_sort_history(self, sort_history): history = [] @@ -298,11 +302,27 @@ class BooksView(QTableView): # {{{ old_state['column_sizes'][name] += 12 return old_state - def restore_state(self): + def get_old_state(self): + ans = None name = unicode(self.objectName()) - old_state = None if name: - old_state = gprefs.get(name + ' books view state', None) + name += ' books view state' + db = getattr(self.model(), 'db', None) + if db is not None: + ans = db.prefs.get(name, None) + if ans is None: + ans = gprefs.get(name, None) + try: + del gprefs[name] + except: + pass + if ans is not None: + db.prefs[name] = ans + return ans + + + def restore_state(self): + old_state = self.get_old_state() if old_state is None: old_state = self.get_default_state() @@ -370,7 +390,7 @@ class BooksView(QTableView): # {{{ # Context Menu {{{ def set_context_menu(self, edit_metadata, send_to_device, convert, view, - save, open_folder, book_details, delete, + save, open_folder, book_details, delete, conn_share, similar_menu=None, add_to_library=None, edit_device_collections=None): self.setContextMenuPolicy(Qt.DefaultContextMenu) @@ -381,6 +401,8 @@ class BooksView(QTableView): # {{{ self.context_menu.addAction(send_to_device) if convert is not None: self.context_menu.addAction(convert) + if conn_share is not None: + self.context_menu.addAction(conn_share) self.context_menu.addAction(view) self.context_menu.addAction(save) if open_folder is not None: @@ -507,6 +529,19 @@ class DeviceBooksView(BooksView): # {{{ self.context_menu.popup(event.globalPos()) event.accept() + def get_old_state(self): + ans = None + name = unicode(self.objectName()) + if name: + name += ' books view state' + ans = gprefs.get(name, None) + return ans + + def write_state(self, state): + name = unicode(self.objectName()) + if name: + gprefs.set(name + ' books view state', state) + def set_database(self, db): self._model.set_database(db) self.restore_state() diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index dd7d0a63a0..cb6791bb3b 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -10,13 +10,12 @@ import re from PyQt4.Qt import QComboBox, Qt, QLineEdit, QStringList, pyqtSlot, \ pyqtSignal, SIGNAL, QObject, QDialog, QCompleter, \ - QAction, QKeySequence + QAction, QKeySequence, QTimer from calibre.gui2 import config from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.saved_search_editor import SavedSearchEditor from calibre.gui2.dialogs.search import SearchDialog -from calibre.utils.config import prefs from calibre.utils.search_query_parser import saved_searches class SearchLineEdit(QLineEdit): @@ -83,7 +82,9 @@ class SearchBox2(QComboBox): self.help_state = False self.as_you_type = True self.prev_search = '' - self.timer = None + self.timer = QTimer() + self.timer.setSingleShot(True) + self.timer.timeout.connect(self.timer_event, type=Qt.QueuedConnection) self.setInsertPolicy(self.NoInsert) self.setMaxCount(self.MAX_COUNT) self.setSizeAdjustPolicy(self.AdjustToMinimumContentsLengthWithIcon) @@ -117,9 +118,6 @@ class SearchBox2(QComboBox): self.search.emit('') self._in_a_search = False self.setEditText(self.help_text) - if self.timer is not None: # Turn off any timers that got started in setEditText - self.killTimer(self.timer) - self.timer = None self.line_edit.home(False) self.line_edit.setStyleSheet( 'QLineEdit { color: gray; background-color: %s; }' % @@ -148,18 +146,15 @@ class SearchBox2(QComboBox): self._in_a_search = False if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.do_search() - self.timer = self.startTimer(self.__class__.INTERVAL) + self.timer.start(1500) def mouse_released(self, event): self.normalize_state() if self.as_you_type: - self.timer = self.startTimer(self.__class__.INTERVAL) + self.timer.start(1500) - def timerEvent(self, event): - self.killTimer(event.timerId()) - if event.timerId() == self.timer: - self.timer = None - self.do_search() + def timer_event(self): + self.do_search() def history_selected(self, text): self.emit(SIGNAL('changed()')) @@ -213,9 +208,6 @@ class SearchBox2(QComboBox): return self.normalize_state() self.setEditText(txt) - if self.timer is not None: # Turn off any timers that got started in setEditText - self.killTimer(self.timer) - self.timer = None self.search.emit(txt) self.line_edit.end(False) self.initial_state = False @@ -259,8 +251,7 @@ class SavedSearchBox(QComboBox): self.setMinimumContentsLength(10) self.tool_tip_text = self.toolTip() - def initialize(self, _saved_searches, _search_box, colorize=False, help_text=_('Search')): - self.saved_searches = _saved_searches + def initialize(self, _search_box, colorize=False, help_text=_('Search')): self.search_box = _search_box self.help_text = help_text self.colorize = colorize @@ -302,11 +293,11 @@ class SavedSearchBox(QComboBox): self.normalize_state() self.search_box.set_search_string(u'search:"%s"' % qname) self.setEditText(qname) - self.setToolTip(self.saved_searches.lookup(qname)) + self.setToolTip(saved_searches().lookup(qname)) def initialize_saved_search_names(self): self.clear() - qnames = self.saved_searches.names() + qnames = saved_searches().names() self.addItems(qnames) self.setCurrentIndex(-1) @@ -319,10 +310,10 @@ class SavedSearchBox(QComboBox): idx = self.currentIndex if idx < 0: return - ss = self.saved_searches.lookup(unicode(self.currentText())) + ss = saved_searches().lookup(unicode(self.currentText())) if ss is None: return - self.saved_searches.delete(unicode(self.currentText())) + saved_searches().delete(unicode(self.currentText())) self.clear_to_help() self.search_box.clear_to_help() self.emit(SIGNAL('changed()')) @@ -332,8 +323,8 @@ class SavedSearchBox(QComboBox): name = unicode(self.currentText()) if self.help_state or not name.strip(): name = unicode(self.search_box.text()).replace('"', '') - self.saved_searches.delete(name) - self.saved_searches.add(name, unicode(self.search_box.text())) + saved_searches().delete(name) + saved_searches().add(name, unicode(self.search_box.text())) # now go through an initialization cycle to ensure that the combobox has # the new search in it, that it is selected, and that the search box # references the new search instead of the text in the search. @@ -348,7 +339,7 @@ class SavedSearchBox(QComboBox): idx = self.currentIndex(); if idx < 0: return - self.search_box.set_search_string(self.saved_searches.lookup(unicode(self.currentText()))) + self.search_box.set_search_string(saved_searches().lookup(unicode(self.currentText()))) class SearchBoxMixin(object): @@ -390,11 +381,12 @@ class SearchBoxMixin(object): class SavedSearchBoxMixin(object): - def __init__(self): + def __init__(self, db): + self.db = db self.connect(self.saved_search, SIGNAL('changed()'), self.saved_searches_changed) self.saved_searches_changed() self.connect(self.clear_button, SIGNAL('clicked()'), self.saved_search.clear_to_help) - self.saved_search.initialize(saved_searches, self.search, colorize=True, + self.saved_search.initialize(self.search, colorize=True, help_text=_('Saved Searches')) self.connect(self.save_search_button, SIGNAL('clicked()'), self.saved_search.save_search_button_clicked) @@ -409,9 +401,12 @@ class SavedSearchBoxMixin(object): b = getattr(self, x+'_search_button') b.setStatusTip(b.toolTip()) + def set_database(self, db): + self.db = db + self.saved_searches_changed() def saved_searches_changed(self): - p = prefs['saved_searches'].keys() + p = saved_searches().names() p.sort() t = unicode(self.search_restriction.currentText()) self.search_restriction.clear() # rebuild the restrictions combobox using current saved searches diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 2a9fb129ac..1565520ca1 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -17,7 +17,6 @@ from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \ from calibre.ebooks.metadata import title_sort from calibre.gui2 import config, NONE -from calibre.utils.config import prefs from calibre.library.field_metadata import TagsIcons from calibre.utils.search_query_parser import saved_searches from calibre.gui2 import error_dialog @@ -224,7 +223,7 @@ class TagsView(QTreeView): # {{{ # Always show the user categories editor self.context_menu.addSeparator() - if category in prefs['user_categories'].keys(): + if category in self.db.prefs.get('user_categories', {}).keys(): self.context_menu.addAction(_('Manage User Categories'), partial(self.context_menu_handler, action='manage_categories', category=category)) @@ -426,10 +425,10 @@ class TagsModel(QAbstractItemModel): # {{{ for k in tb_cats.keys(): if tb_cats[k]['kind'] in ['user', 'search']: del tb_cats[k] - for user_cat in sorted(prefs['user_categories'].keys()): + for user_cat in sorted(self.db.prefs.get('user_categories', {}).keys()): cat_name = user_cat+':' # add the ':' to avoid name collision tb_cats.add_user_category(label=cat_name, name=user_cat) - if len(saved_searches.names()): + if len(saved_searches().names()): tb_cats.add_search_category(label='search', name=_('Searches')) # Now get the categories @@ -507,11 +506,11 @@ class TagsModel(QAbstractItemModel): # {{{ if key not in self.db.field_metadata: return if key == 'search': - if val in saved_searches.names(): + if val in saved_searches().names(): error_dialog(self.tags_view, _('Duplicate search name'), _('The saved search name %s is already used.')%val).exec_() return False - saved_searches.rename(unicode(item.data(role).toString()), val) + saved_searches().rename(unicode(item.data(role).toString()), val) self.tags_view.search_item_renamed.emit() else: if key == 'series': diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 72f7202504..ec8d07bdbe 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -199,7 +199,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ UpdateMixin.__init__(self, opts) ####################### Search boxes ######################## - SavedSearchBoxMixin.__init__(self) + SavedSearchBoxMixin.__init__(self, db) SearchBoxMixin.__init__(self) ####################### Library view ######################## @@ -351,7 +351,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ return self.memory_view.model().db, self.card_a_view.model().db, self.card_b_view.model().db - def do_config(self, *args): + def do_config(self, checked=False, initial_category='general'): if self.job_manager.has_jobs(): d = error_dialog(self, _('Cannot configure'), _('Cannot configure while there are running jobs.')) @@ -363,7 +363,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ d.exec_() return d = ConfigDialog(self, self.library_view, - server=self.content_server) + server=self.content_server, initial_category=initial_category) d.exec_() self.content_server = d.server @@ -380,6 +380,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.tags_view.recount() self.create_device_menu() self.set_device_menu_items_state(bool(self.device_connected)) + self.tool_bar.apply_settings() def library_moved(self, newloc): if newloc is None: return @@ -392,6 +393,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.library_view.model().set_book_on_device_func(self.book_on_device) self.status_bar.clear_message() self.search.clear_to_help() + self.saved_search.clear_to_help() self.book_details.reset_info() self.library_view.model().count_changed() self.scheduler.database_changed(db) diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index bd4bd0a01a..4653529095 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -448,7 +448,7 @@ class DocumentView(QWebView): self.unimplemented_actions = list(map(self.pageAction, [d.DownloadImageToDisk, d.OpenLinkInNewWindow, d.DownloadLinkToDisk, d.OpenImageInNewWindow, d.OpenLink])) - self.dictionary_action = QAction(QIcon(I('dictionary.png')), + self.dictionary_action = QAction(QIcon(I('dictionary.svg')), _('&Lookup in dictionary'), self) self.dictionary_action.setShortcut(Qt.CTRL+Qt.Key_L) self.dictionary_action.triggered.connect(self.lookup) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 85e951d4b0..e3530d3801 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -19,6 +19,7 @@ from calibre.library.schema_upgrades import SchemaUpgrade from calibre.library.caches import ResultCache from calibre.library.custom_columns import CustomColumns from calibre.library.sqlite import connect, IntegrityError, DBThread +from calibre.library.prefs import DBPrefs from calibre.ebooks.metadata import string_to_authors, authors_to_string, \ MetaInformation from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats @@ -29,7 +30,7 @@ from calibre.customize.ui import run_plugins_on_import from calibre.utils.filenames import ascii_filename from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp from calibre.utils.config import prefs, tweaks -from calibre.utils.search_query_parser import saved_searches +from calibre.utils.search_query_parser import saved_searches, set_saved_searches from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format from calibre.utils.magick_draw import save_cover_data_to @@ -140,6 +141,21 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.initialize_dynamic() def initialize_dynamic(self): + self.prefs = DBPrefs(self) + + # Migrate saved search and user categories to db preference scheme + def migrate_preference(key, default): + oldval = prefs[key] + if oldval != default: + self.prefs[key] = oldval + prefs[key] = default + if key not in self.prefs: + self.prefs[key] = default + + migrate_preference('user_categories', {}) + migrate_preference('saved_searches', {}) + set_saved_searches(self, 'saved_searches') + self.conn.executescript(''' DROP TRIGGER IF EXISTS author_insert_trg; CREATE TEMP TRIGGER author_insert_trg @@ -268,10 +284,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): for k in tb_cats.keys(): if tb_cats[k]['kind'] in ['user', 'search']: del tb_cats[k] - for user_cat in sorted(prefs['user_categories'].keys()): + for user_cat in sorted(self.prefs.get('user_categories', {}).keys()): cat_name = user_cat+':' # add the ':' to avoid name collision tb_cats.add_user_category(label=cat_name, name=user_cat) - if len(saved_searches.names()): + if len(saved_searches().names()): tb_cats.add_search_category(label='search', name=_('Searches')) self.book_on_device_func = None @@ -843,7 +859,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): categories['formats'].sort(key = lambda x:x.name) #### Now do the user-defined categories. #### - user_categories = prefs['user_categories'] + user_categories = self.prefs['user_categories'] # We want to use same node in the user category as in the source # category. To do that, we need to find the original Tag node. There is @@ -880,8 +896,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): icon = None if icon_map and 'search' in icon_map: icon = icon_map['search'] - for srch in saved_searches.names(): - items.append(Tag(srch, tooltip=saved_searches.lookup(srch), icon=icon)) + for srch in saved_searches().names(): + items.append(Tag(srch, tooltip=saved_searches().lookup(srch), icon=icon)) if len(items): if icon_map is not None: icon_map['search'] = icon_map['search'] diff --git a/src/calibre/library/prefs.py b/src/calibre/library/prefs.py new file mode 100644 index 0000000000..ff9733aaa3 --- /dev/null +++ b/src/calibre/library/prefs.py @@ -0,0 +1,49 @@ +#!/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 json + +from calibre.constants import preferred_encoding +from calibre.utils.config import to_json, from_json + +class DBPrefs(dict): + + def __init__(self, db): + dict.__init__(self) + self.db = db + for key, val in self.db.conn.get('SELECT key,val FROM preferences'): + val = self.raw_to_object(val) + dict.__setitem__(self, key, val) + + def raw_to_object(self, raw): + if not isinstance(raw, unicode): + raw = raw.decode(preferred_encoding) + return json.loads(raw, object_hook=from_json) + + def to_raw(self, val): + return json.dumps(val, indent=2, default=to_json) + + def __getitem__(self, key): + return dict.__getitem__(self, key) + + def __delitem__(self, key): + dict.__delitem__(self, key) + self.db.conn.execute('DELETE FROM preferences WHERE key=?', (key,)) + self.db.conn.commit() + + def __setitem__(self, key, val): + raw = self.to_raw(val) + self.db.conn.execute('DELETE FROM preferences WHERE key=?', (key,)) + self.db.conn.execute('INSERT INTO preferences (key,val) VALUES (?,?)', (key, + raw)) + self.db.conn.commit() + dict.__setitem__(self, key, val) + + def set(self, key, val): + self.__setitem__(key, val) + + diff --git a/src/calibre/library/schema_upgrades.py b/src/calibre/library/schema_upgrades.py index 1ba650f6fd..b08161abf2 100644 --- a/src/calibre/library/schema_upgrades.py +++ b/src/calibre/library/schema_upgrades.py @@ -387,3 +387,13 @@ class SchemaUpgrade(object): self.conn.execute('UPDATE authors SET sort=author_to_author_sort(name)') + def upgrade_version_12(self): + 'DB based preference store' + script = ''' + DROP TABLE IF EXISTS preferences; + CREATE TABLE preferences(id INTEGER PRIMARY KEY, + key TEXT NON NULL, + val TEXT NON NULL, + UNIQUE(key)); + ''' + self.conn.executescript(script) diff --git a/src/calibre/manual/conversion.rst b/src/calibre/manual/conversion.rst index 7df11575de..c8bc3ef665 100644 --- a/src/calibre/manual/conversion.rst +++ b/src/calibre/manual/conversion.rst @@ -349,7 +349,7 @@ table of contents, check the :guilabel:`Do not add detected chapters` option. If less than the :guilabel:`Chapter threshold` number of chapters were detected, |app| will then add any hyperlinks it finds in the input document to the Table of Contents. This often works well many input documents include a -hyperlinked Table of Contents right at the start. The :guilabel:`Number fo links` option can be used to control +hyperlinked Table of Contents right at the start. The :guilabel:`Number of links` option can be used to control this behavior. If set to zero, no links are added. If set to a number greater than zero, at most that number of links is added. diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 77dc4a9c2b..8ba38ad6bc 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.9\n" -"POT-Creation-Date: 2010-07-17 19:33+MDT\n" -"PO-Revision-Date: 2010-07-17 19:33+MDT\n" +"POT-Creation-Date: 2010-07-20 16:32+MDT\n" +"PO-Revision-Date: 2010-07-20 16:32+MDT\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -41,7 +41,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:235 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:278 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:281 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:395 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:397 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:20 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:21 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/ereader.py:36 @@ -110,15 +110,15 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:110 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:137 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:897 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:906 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1189 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1192 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:855 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:864 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1149 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1152 #: /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 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:481 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:173 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:362 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:382 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:882 @@ -128,18 +128,18 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:185 #: /home/kovid/work/calibre/src/calibre/library/cli.py:213 #: /home/kovid/work/calibre/src/calibre/library/database.py:913 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:339 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:351 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:954 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1023 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1624 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1626 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1748 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:355 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:367 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:970 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1039 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1640 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1642 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1764 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:268 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:134 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:137 #: /home/kovid/work/calibre/src/calibre/library/server/xml.py:68 -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:115 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:117 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:46 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:64 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:78 @@ -476,10 +476,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:807 #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:813 #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:841 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:243 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:171 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:184 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1508 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:244 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:187 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:200 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1524 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:132 msgid "News" msgstr "" @@ -1594,7 +1594,7 @@ msgstr "" msgid "Comic" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:394 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:396 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/info.py:45 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:97 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:98 @@ -1607,7 +1607,7 @@ msgstr "" msgid "Title" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:395 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:397 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:59 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:67 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:364 @@ -1615,18 +1615,18 @@ msgstr "" msgid "Author(s)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:396 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:398 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:61 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:72 msgid "Publisher" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:397 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:399 #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/manipulate/info.py:49 msgid "Producer" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:398 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:400 #: /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 @@ -1638,9 +1638,9 @@ msgstr "" msgid "Comments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:406 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:408 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:27 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:45 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:73 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:306 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1075 @@ -1648,9 +1648,9 @@ msgstr "" msgid "Tags" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:408 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:410 #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:26 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:45 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:74 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:323 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1084 @@ -1658,22 +1658,22 @@ msgstr "" msgid "Series" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:409 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:411 msgid "Language" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:411 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:413 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1067 msgid "Timestamp" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:413 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:415 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:63 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:70 msgid "Published" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:415 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:417 msgid "Rights" msgstr "" @@ -2576,14 +2576,14 @@ msgid "Main memory" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions.py:519 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:445 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:454 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:423 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:432 msgid "Storage Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions.py:520 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:447 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:456 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:425 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:434 msgid "Storage Card B" msgstr "" @@ -2641,9 +2641,9 @@ msgid "Failed to download metadata:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions.py:659 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:638 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:515 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:923 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:595 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:541 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:953 #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:53 msgid "Error" msgstr "" @@ -2793,7 +2793,7 @@ msgid "The specified directory could not be processed." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:263 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:839 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:797 msgid "No books" msgstr "" @@ -2907,14 +2907,14 @@ msgstr "" #: /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:528 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:529 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:541 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:543 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:545 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:547 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:548 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:588 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:560 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:562 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:564 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:566 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:567 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:610 #: /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 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:379 @@ -2976,7 +2976,7 @@ 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:220 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:230 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:312 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:100 msgid "Formats" @@ -3158,8 +3158,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:20 #: /home/kovid/work/calibre/src/calibre/library/catalog.py:550 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1471 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1489 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1487 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1505 msgid "Catalog" msgstr "" @@ -4219,205 +4219,186 @@ msgstr "" msgid "View book on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:408 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:406 msgid "Set default send to device action" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:414 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:421 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:423 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:425 -msgid "Email to" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:425 -msgid " and delete from library" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:434 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:412 msgid "Send to main memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:436 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:414 msgid "Send to storage card A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:438 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:416 msgid "Send to storage card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:443 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:452 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:421 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:430 msgid "Main Memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:470 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:441 msgid "Send and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:471 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:442 msgid "Send specific format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:510 -msgid "Connect to folder" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:516 -msgid "Connect to iTunes" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:521 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:478 msgid "Eject device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:529 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:486 msgid "Fetch annotations (experimental)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:639 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:596 msgid "Error communicating with device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:659 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:618 msgid "Select folder to open as device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:704 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:662 msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:710 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:668 msgid "Error talking to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:711 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:669 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:753 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:711 msgid "Device: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:755 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:713 msgid " detected." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:840 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:798 msgid "selected to send" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:845 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:803 msgid "Choose format to send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:854 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:812 msgid "No device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:855 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:813 msgid "Cannot send: No device is connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:858 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:862 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:816 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:820 msgid "No card" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:859 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:863 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:817 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:821 msgid "Cannot send: Device has no storage card" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:904 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:862 msgid "E-book:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:907 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:865 msgid "Attached, you will find the e-book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:908 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:866 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:181 msgid "by" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:909 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:867 msgid "in the %s format." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:922 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:880 msgid "Sending email to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:952 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:960 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1052 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1114 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1233 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1241 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:910 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:918 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1012 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1074 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1193 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1201 msgid "No suitable formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:953 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:911 msgid "Auto convert the following books before sending via email?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:961 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:919 msgid "Could not email the following books as no suitable formats were found:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:979 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:937 msgid "Failed to email books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:980 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:938 msgid "Failed to email the following books:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:984 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:942 msgid "Sent by email:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1011 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:971 msgid "News:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1012 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:972 msgid "Attached is the" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1023 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:983 msgid "Sent news to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1053 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1115 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1234 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1013 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1075 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1194 msgid "Auto convert the following books before uploading to the device?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1083 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1043 msgid "Sending catalogs to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1147 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1107 msgid "Sending news to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1200 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1160 msgid "Sending books to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1242 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1202 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:1304 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1264 msgid "No space on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1305 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1265 msgid "

Cannot upload books to device there is no more free space available " msgstr "" @@ -4514,14 +4495,6 @@ msgstr "" msgid "The folder %s is not empty. Please choose an empty folder" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:66 -msgid "Custom columns" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library.py:67 -msgid "If you use custom columns and they differ between libraries, you will have various problems. Best to ensure you have the same custom columns in each library." -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_library_ui.py:66 msgid "Choose your calibre library" msgstr "" @@ -4584,11 +4557,7 @@ msgid "" "Customization: " 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:200 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:199 msgid "General" msgstr "" @@ -4597,180 +4566,208 @@ msgid "Interface" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:201 -msgid "Add/Save" +msgid "Conversion" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:201 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:202 msgid "" "Email\n" "Delivery" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:202 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:203 +msgid "Add/Save" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:204 msgid "Advanced" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:202 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:205 msgid "" "Content\n" "Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:202 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:206 msgid "Plugins" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:220 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:230 msgid "Auto send" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:220 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:230 msgid "Email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:225 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:235 msgid "Formats to email. The first matching format will be sent." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:226 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:236 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:300 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:310 msgid "new email address" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:482 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:492 msgid "Wide" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:483 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:493 msgid "Narrow" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:495 -msgid "System port selected" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:502 +msgid "Medium" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:496 -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." +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:502 +msgid "Small" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:516 -msgid "Failed to install command line tools." +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:503 +msgid "Large" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:519 -msgid "Command line tools installed" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:509 +msgid "Always" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:520 -msgid "Command line tools installed in" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:509 +msgid "Automatic" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:510 +msgid "Never" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:521 +msgid "System port selected" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:522 +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:542 +msgid "Failed to install command line tools." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:545 +msgid "Command line tools installed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:546 +msgid "Command line tools installed in" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:547 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:572 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:598 msgid "No valid plugin path" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:573 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:599 msgid "%s is not a valid plugin path" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:576 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:602 msgid "Choose plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:588 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:614 msgid "Plugin cannot be disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:589 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:615 msgid "The plugin: %s cannot be disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:598 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:624 msgid "Plugin not customizable" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:599 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:625 msgid "Plugin: %s does not need customization" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:607 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:633 msgid "Customize" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:645 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:671 msgid "Cannot remove builtin plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:646 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:672 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:677 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:703 msgid "You must select a column to delete it" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:682 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:708 msgid "The selected column is not a custom column" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:683 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:709 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:48 msgid "Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:684 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:710 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:751 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:777 msgid "Error log:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:758 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:784 msgid "Access log:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:786 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:812 #: /home/kovid/work/calibre/src/calibre/gui2/ui.py:312 msgid "Failed to start content server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:811 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:837 msgid "Invalid size" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:812 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:838 msgid "The size %s is invalid. must be of the form widthxheight" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:869 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:899 msgid "Must restart" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:870 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:900 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:904 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:934 msgid "Checking database integrity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:924 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:954 msgid "Failed to check database integrity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:929 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:959 msgid "Some inconsistencies found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:930 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:960 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 "" @@ -4885,285 +4882,297 @@ msgstr "" msgid "Sending to &device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:514 -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:386 -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:523 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:533 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:458 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:599 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:201 msgid "Preferences" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:515 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:534 msgid "Show notification when &new version is available" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:516 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:535 msgid "Download &social metadata (tags/ratings/etc.) by default" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:517 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:536 msgid "&Overwrite author and title by default when fetching metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:518 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:537 msgid "Default network &timeout:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:519 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:538 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:520 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:539 msgid " seconds" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:521 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:540 msgid "Choose &language (requires restart):" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:522 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:541 msgid "Normal" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:523 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:542 msgid "High" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:524 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:543 msgid "Low" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:525 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:544 msgid "Job &priority:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:526 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:545 msgid "Preferred &output format:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:527 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:546 msgid "Preferred &input format order:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:530 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:549 msgid "Use &Roman numerals for series number" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:531 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:550 msgid "Enable system &tray icon (needs restart)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:532 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:551 msgid "Show ¬ifications in system tray" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:533 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:552 msgid "Show &splash screen at startup" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:534 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:553 msgid "Show cover &browser in a separate window (needs restart)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:535 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:554 msgid "Show &average ratings in the tags browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:536 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:555 msgid "Search as you type" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:537 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:556 msgid "Automatically send downloaded &news to ebook reader" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:538 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:557 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:539 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:558 msgid "&Number of covers to show in browse mode (needs restart):" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:540 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:559 msgid "Select visible &columns in library view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:542 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:561 msgid "Remove a user-defined column" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:544 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:563 msgid "Add a user-defined column" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:546 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:565 msgid "Edit settings of a user-defined column" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:549 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:568 msgid "Use internal &viewer for:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:550 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:569 msgid "User Interface &layout (needs restart):" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:551 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:570 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:552 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:571 msgid "Disable &animations" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:553 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:572 msgid "Show &donate button (restart)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:554 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:573 +msgid "&Toolbar" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:574 +msgid "&Icon size:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:575 +msgid "Show &text under icons:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:576 msgid "Add an email address to which to send books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:555 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:577 msgid "&Add email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:556 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:578 msgid "Make &default" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:557 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:579 msgid "&Remove email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:558 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:580 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:559 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:581 msgid "&Maximum number of waiting worker processes (needs restart):" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:560 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:582 msgid "&Check database integrity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:561 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:583 msgid "&Install command line tools" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:562 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:584 msgid "Open calibre &configuration directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:563 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:585 msgid "Limit the max. simultaneous jobs to the available CPU &cores" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:564 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:586 msgid "Debug &device detection" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:565 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:587 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:566 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:588 msgid "Server &port:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:567 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:589 #: /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:568 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:590 #: /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:569 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:591 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:570 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:592 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:571 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:593 msgid "Max. &cover size:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:572 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:594 #: /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:573 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:595 msgid "Max. &OPDS items per query:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:574 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:596 msgid "Max. OPDS &ungrouped items:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:575 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:597 msgid "&Start Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:576 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:598 msgid "St&op Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:577 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:599 msgid "&Test Server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:578 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:600 msgid "Run server &automatically on startup" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:579 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:601 msgid "View &server logs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:580 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:602 #: /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:582 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:604 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:583 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:605 msgid "Enable/&Disable plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:584 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:606 msgid "&Customize plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:585 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:607 msgid "&Remove plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:586 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:608 msgid "Add new plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:587 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:609 msgid "Plugin &file:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:589 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:611 msgid "&Add" msgstr "" @@ -5543,7 +5552,7 @@ msgid "Show job &details" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:47 -msgid "Stop &all jobs" +msgid "Stop &all non device jobs" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:24 @@ -5885,48 +5894,48 @@ msgstr "" msgid "Change the contents of the saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:119 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:120 msgid "Need username and password" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:120 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:121 msgid "You must provide a username and/or password to use this news source." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:171 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:172 msgid "Created by: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:178 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:179 msgid "Last downloaded: never" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:193 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:194 msgid "%d days, %d hours and %d minutes ago" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:195 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:196 msgid "Last downloaded" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:219 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:220 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:192 msgid "Schedule news download" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:222 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:223 msgid "Add a custom news source" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:227 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:228 msgid "Download all scheduled new sources" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:327 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:328 msgid "No internet connection" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:329 msgid "Cannot download news as no internet connection is active" msgstr "" @@ -6110,21 +6119,21 @@ msgstr "" msgid "Choose formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:45 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:80 msgid "Authors" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:45 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:111 msgid "Publishers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:110 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:109 msgid " (not on any book)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:161 msgid "The current tag category will be permanently deleted. Are you sure?" msgstr "" @@ -6226,12 +6235,12 @@ msgid "%s (was %s)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:70 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:501 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:500 msgid "Item is blank" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:71 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:502 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:501 msgid "An item cannot be set to nothing. Delete it instead." msgstr "" @@ -6536,42 +6545,42 @@ msgstr "" msgid "Similar books..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:65 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:66 msgid "Add books to library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:67 -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:74 -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:81 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:76 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:84 msgid "Manage collections" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:161 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:165 msgid "Cover Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:179 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:183 msgid "Tag Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:200 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:204 msgid "version" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:201 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:205 msgid "created by Kovid Goyal" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:219 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:223 msgid "Connected " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:228 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:232 msgid "Update found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:272 -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:281 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:276 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:285 msgid "Book Details" msgstr "" @@ -6660,7 +6669,7 @@ msgid "Show books in the main memory of the device" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:89 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:551 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:567 msgid "Card A" msgstr "" @@ -6669,7 +6678,7 @@ msgid "Show books in storage card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:91 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:553 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:569 msgid "Card B" msgstr "" @@ -6709,225 +6718,251 @@ msgstr "" msgid "Delete current saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:290 -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:379 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:302 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:451 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:108 msgid "%d books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:334 +msgid "Connect to folder" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:340 +msgid "Connect to iTunes" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:354 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:360 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:362 +msgid "Email to" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:362 +msgid " and delete from library" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:373 +msgid "Setup email based sharing of books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:446 msgid "A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:446 msgid "Add books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:376 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:447 msgid "E" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:376 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:447 msgid "Edit metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:377 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:448 msgid "C" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:377 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:448 msgid "Convert books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:378 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:449 msgid "V" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:378 -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:475 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:449 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:551 msgid "View" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:380 -msgid "Choose calibre library to work with" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:381 -msgid "F" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:381 -msgid "Fetch news" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:382 -msgid "S" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:382 -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:458 -msgid "Save to disk" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:383 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:450 msgid "Send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:384 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:452 +msgid "Choose calibre library to work with" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:453 +msgid "F" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:453 +msgid "Fetch news" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:454 +msgid "S" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:454 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:534 +msgid "Save to disk" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:455 +msgid "Connect/share" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:456 msgid "Del" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:384 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:456 msgid "Remove books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:385 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:457 msgid "Browse the calibre User Manual" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:385 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:457 msgid "F1" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:385 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:457 msgid "Help" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:386 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:458 msgid "Ctrl+P" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:388 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:460 msgid "M" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:388 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:460 msgid "Merge book records" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:389 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:461 msgid "Open containing folder" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:391 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:463 msgid "Show book details" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:393 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:465 msgid "Books by same author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:395 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:467 msgid "Books in this series" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:397 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:469 msgid "Books by this publisher" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:399 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:471 msgid "Books with the same tags" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:408 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:484 msgid "Edit metadata individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:411 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:487 msgid "Edit metadata in bulk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:414 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:490 msgid "Download metadata and covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:417 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:493 msgid "Download only metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:419 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:495 msgid "Download only covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:422 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:498 msgid "Download only social metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:428 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:504 msgid "Merge into first selected book - delete others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:431 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:507 msgid "Merge into first selected book - keep others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:439 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:515 msgid "Add books from a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:441 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:517 msgid "Add books from directories, including sub-directories (One book per directory, assumes every ebook file is the same book in a different format)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:445 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:521 msgid "Add books from directories, including sub directories (Multiple books per directory, assumes every ebook file is a different book)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:448 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:524 msgid "Add Empty book. (Book entry with no formats)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:460 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:536 msgid "Save to disk in a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:462 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:538 #: /home/kovid/work/calibre/src/calibre/gui2/ui.py:374 msgid "Save only %s format to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:466 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:542 #: /home/kovid/work/calibre/src/calibre/gui2/ui.py:377 msgid "Save only %s format to disk in a single directory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:476 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:552 msgid "View specific format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:482 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:558 msgid "Remove selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:484 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:560 msgid "Remove files of a specific format from selected books.." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:487 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:563 msgid "Remove all formats from selected books, except..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:490 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:566 msgid "Remove covers from selected books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:493 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:569 msgid "Remove matching books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:510 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:586 msgid "Convert individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:512 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:588 msgid "Bulk convert" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:516 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:592 msgid "Create catalog of books in your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:524 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:600 msgid "Run welcome wizard" msgstr "" @@ -6958,7 +6993,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:679 #: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1182 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:399 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:398 msgid "The lookup/search name is \"{0}\"" msgstr "" @@ -7018,11 +7053,11 @@ msgstr "" msgid "Restore default layout" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:525 +#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:560 msgid "Not allowed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:526 +#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:561 msgid "Dropping onto a device is not supported. First add the book to the calibre library." msgstr "" @@ -7236,25 +7271,25 @@ msgstr "" msgid "No matches found for this book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:93 -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:262 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:94 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:254 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:554 msgid "Search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:315 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:306 msgid "The selected search will be permanently deleted. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:357 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:348 msgid "Search (For Advanced Search click the button to the left)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:398 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:390 msgid "Saved Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:406 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:398 msgid "Choose saved search or enter name for new saved search" msgstr "" @@ -7335,86 +7370,86 @@ msgstr "" msgid "&Alternate shortcut:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:191 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:190 msgid "Rename '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:195 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:194 msgid "Edit sort for '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:200 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:199 msgid "Hide category %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:203 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:202 msgid "Show category" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:207 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:206 msgid "Show all categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:214 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:218 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:213 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:217 msgid "Manage %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:221 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:220 msgid "Manage Saved Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:228 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:232 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:227 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:231 msgid "Manage User Categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:433 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:275 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:432 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:291 msgid "Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:511 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:510 msgid "Duplicate search name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:512 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:511 msgid "The saved search name %s is already used." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:768 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:767 msgid "Sort by name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:768 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:767 msgid "Sort by popularity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:769 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:768 msgid "Sort by average rating" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:772 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:771 msgid "Set the sort order for entries in the Tag Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:778 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:777 msgid "Match all" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:778 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:777 msgid "Match any" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:783 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:782 msgid "When selecting multiple entries in the Tag Browser match any or all of them" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:787 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:786 msgid "Manage &user categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:790 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:789 msgid "Add your own categories to the Tag Browser" msgstr "" @@ -7486,51 +7521,51 @@ msgstr "" msgid "Cannot configure before calibre is restarted." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:402 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:404 msgid "No detailed info available" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:403 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:405 msgid "No detailed information is available for books on the device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:455 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:483 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:457 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:485 msgid "Conversion Error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:456 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:458 msgid "

Could not convert: %s

It is a DRMed book. You must first remove the DRM using third party tools." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:469 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:471 msgid "Recipe Disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:484 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:486 msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:524 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:526 msgid "is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development. Your donation helps keep calibre development going." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:550 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:552 msgid "There are active jobs. Are you sure you want to quit?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:553 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:555 msgid "" " is communicating with the device!
\n" " Quitting may cause corruption on the device.
\n" " Are you sure you want to quit?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:557 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:559 msgid "WARNING: Active jobs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:610 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:612 msgid "will keep running in the system tray. To close it, choose Quit in the context menu of the system tray." msgstr "" @@ -8772,35 +8807,35 @@ msgid "" "For help on an individual command: %%prog command --help\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:70 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:71 msgid "%sAverage rating is %3.1f" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:549 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:565 msgid "Main" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1774 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1790 msgid "

Migrating old database to ebook library in %s

" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1803 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1819 msgid "Copying %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1820 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1836 msgid "Compacting database" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1913 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1929 msgid "Checking SQL integrity..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1954 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1970 msgid "Checking for missing files." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1976 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1992 msgid "Checked id" msgstr "" @@ -8991,76 +9026,76 @@ msgstr "" msgid "Newest" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:48 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:49 msgid "" "%sUsage%s: %s\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:92 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:93 msgid "Created by " msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:93 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:94 msgid "Whenever you pass arguments to %prog that have spaces in them, enclose the arguments in quotation marks." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:670 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:678 msgid "Path to the database in which books are stored" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:672 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:680 msgid "Pattern to guess metadata from filenames" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:674 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:682 msgid "Access key for isbndb.com" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:676 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:684 msgid "Default timeout for network operations (seconds)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:678 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:686 msgid "Path to directory in which your library of books is stored" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:680 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:688 msgid "The language in which to display the user interface" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:682 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:690 msgid "The default output format for ebook conversions." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:686 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:694 msgid "Ordered list of formats to prefer for input." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:688 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:696 msgid "Read metadata from files" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:690 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:698 msgid "The priority of worker processes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:692 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:700 msgid "Swap author first and last names when reading metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:694 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:702 msgid "Add new formats to existing book records" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:699 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:707 msgid "List of named saved searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:700 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:708 msgid "User-created tag browser categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/config.py:702 +#: /home/kovid/work/calibre/src/calibre/utils/config.py:710 msgid "How and when calibre updates metadata on the device." msgstr "" @@ -9080,91 +9115,91 @@ msgstr "" msgid "Working..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:93 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:95 msgid "Brazilian Portuguese" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:94 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:96 msgid "English (UK)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:95 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:97 msgid "Simplified Chinese" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:96 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:98 msgid "Chinese (HK)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:97 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:99 msgid "Traditional Chinese" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:98 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:100 msgid "English" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:99 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:101 msgid "English (Australia)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:100 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:102 msgid "English (New Zealand)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:101 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:103 msgid "English (Canada)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:102 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:104 msgid "English (India)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:103 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:105 msgid "English (Thailand)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:104 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:106 msgid "English (Cyprus)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:105 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:107 msgid "English (Pakistan)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:106 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:108 msgid "English (Israel)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:107 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:109 msgid "English (Singapore)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:108 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:110 msgid "English (Yemen)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:109 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:111 msgid "English (Ireland)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:110 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:112 msgid "English (China)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:111 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:113 msgid "Spanish (Paraguay)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:112 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:114 msgid "German (AT)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:113 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:115 msgid "Dutch (NL)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/localization.py:114 +#: /home/kovid/work/calibre/src/calibre/utils/localization.py:116 msgid "Dutch (BE)" msgstr "" diff --git a/src/calibre/utils/PythonMagickWand.py b/src/calibre/utils/PythonMagickWand.py index cf9b5d167f..69a17d2297 100644 --- a/src/calibre/utils/PythonMagickWand.py +++ b/src/calibre/utils/PythonMagickWand.py @@ -66,7 +66,7 @@ and save it to a new file. """ -import ctypes, sys, os +import ctypes, sys, os, glob from ctypes import util iswindows = 'win32' in sys.platform or 'win64' in sys.platform isosx = 'darwin' in sys.platform @@ -85,7 +85,8 @@ elif iswindows: _lib = flib if isfrozen else 'CORE_RL_wand_' else: if isfrozen: - _lib = os.path.join(sys.frozen_path, 'libMagickWand.so.2') + _lib = glob.glob(os.path.join(sys.frozen_path, + 'libMagickWand.so.*'))[-1] else: _lib = util.find_library('MagickWand') if _lib is None: diff --git a/src/calibre/utils/config.py b/src/calibre/utils/config.py index 5c4bd55644..91b1dc70cc 100644 --- a/src/calibre/utils/config.py +++ b/src/calibre/utils/config.py @@ -6,15 +6,16 @@ __docformat__ = 'restructuredtext en' ''' Manage application-wide preferences. ''' -import os, re, cPickle, textwrap, traceback, plistlib, json, base64 +import os, re, cPickle, textwrap, traceback, plistlib, json, base64, datetime from copy import deepcopy from functools import partial from optparse import OptionParser as _OptionParser from optparse import IndentedHelpFormatter +from collections import defaultdict + from calibre.constants import terminal_controller, iswindows, isosx, \ __appname__, __version__, __author__, plugins from calibre.utils.lock import LockError, ExclusiveFile -from collections import defaultdict if os.environ.has_key('CALIBRE_CONFIG_DIRECTORY'): config_dir = os.path.abspath(os.environ['CALIBRE_CONFIG_DIRECTORY']) @@ -632,27 +633,34 @@ class XMLConfig(dict): f.truncate() f.write(raw) +def to_json(obj): + if isinstance(obj, bytearray): + return {'__class__': 'bytearray', + '__value__': base64.standard_b64encode(bytes(obj))} + if isinstance(obj, datetime.datetime): + from calibre.utils.date import isoformat + return {'__class__': 'datetime.datetime', + '__value__': isoformat(obj, as_utc=True)} + raise TypeError(repr(obj) + ' is not JSON serializable') + +def from_json(obj): + if '__class__' in obj: + if obj['__class__'] == 'bytearray': + return bytearray(base64.standard_b64decode(obj['__value__'])) + if obj['__class__'] == 'datetime.datetime': + from calibre.utils.date import parse_date + return parse_date(obj['__value__'], assume_utc=True) + return obj + class JSONConfig(XMLConfig): EXTENSION = '.json' - def to_json(self, obj): - if isinstance(obj, bytearray): - return {'__class__': 'bytearray', - '__value__': base64.standard_b64encode(bytes(obj))} - raise TypeError(repr(obj) + ' is not JSON serializable') - - def from_json(self, obj): - if '__class__' in obj: - if obj['__class__'] == 'bytearray': - return bytearray(base64.standard_b64decode(obj['__value__'])) - return obj - def raw_to_object(self, raw): - return json.loads(raw.decode('utf-8'), object_hook=self.from_json) + return json.loads(raw.decode('utf-8'), object_hook=from_json) def to_raw(self): - return json.dumps(self, indent=2, default=self.to_json) + return json.dumps(self, indent=2, default=to_json) def __getitem__(self, key): return dict.__getitem__(self, key) diff --git a/src/calibre/utils/localization.py b/src/calibre/utils/localization.py index e60a3233c6..94f3923acf 100644 --- a/src/calibre/utils/localization.py +++ b/src/calibre/utils/localization.py @@ -42,6 +42,8 @@ def get_lang(): lang = match.group() if lang == 'zh': lang = 'zh_CN' + if lang is None: + lang = 'en' return lang def messages_path(lang): diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index d6bf932b76..f01e40549a 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -21,7 +21,6 @@ import sys, string, operator from calibre.utils.pyparsing import Keyword, Group, Forward, CharsNotIn, Suppress, \ OneOrMore, oneOf, CaselessLiteral, Optional, NoMatch, ParseException from calibre.constants import preferred_encoding -from calibre.utils.config import prefs ''' This class manages access to the preference holding the saved search queries. @@ -32,9 +31,13 @@ class SavedSearchQueries(object): queries = {} opt_name = '' - def __init__(self, _opt_name): + def __init__(self, db, _opt_name): self.opt_name = _opt_name; - self.queries = prefs[self.opt_name] + self.db = db + if db is not None: + self.queries = db.prefs.get(self.opt_name, {}) + else: + self.queries = {} def force_unicode(self, x): if not isinstance(x, unicode): @@ -43,20 +46,20 @@ class SavedSearchQueries(object): def add(self, name, value): self.queries[self.force_unicode(name)] = self.force_unicode(value).strip() - prefs[self.opt_name] = self.queries + self.db.prefs[self.opt_name] = self.queries def lookup(self, name): return self.queries.get(self.force_unicode(name), None) def delete(self, name): self.queries.pop(self.force_unicode(name), False) - prefs[self.opt_name] = self.queries + self.db.prefs[self.opt_name] = self.queries def rename(self, old_name, new_name): self.queries[self.force_unicode(new_name)] = \ self.queries.get(self.force_unicode(old_name), None) self.queries.pop(self.force_unicode(old_name), False) - prefs[self.opt_name] = self.queries + self.db.prefs[self.opt_name] = self.queries def names(self): return sorted(self.queries.keys(), @@ -66,8 +69,15 @@ class SavedSearchQueries(object): Create a global instance of the saved searches. It is global so that the searches are common across all instances of the parser (devices, library, etc). ''' -saved_searches = SavedSearchQueries('saved_searches') +ss = SavedSearchQueries(None, None) +def set_saved_searches(db, opt_name): + global ss + ss = SavedSearchQueries(db, opt_name) + +def saved_searches(): + global ss + return ss class SearchQueryParser(object): ''' @@ -209,7 +219,7 @@ class SearchQueryParser(object): raise ParseException(query, len(query), 'undefined saved search', self) if self.recurse_level > 5: self.searches_seen.add(query) - return self._parse(saved_searches.lookup(query)) + return self._parse(saved_searches().lookup(query)) except: # convert all exceptions (e.g., missing key) to a parse error raise ParseException(query, len(query), 'undefined saved search', self) return self.get_matches(location, query)