Esempio n. 1
0
    def delete_tags(self, item=None):
        confirms, deletes = [], []
        items = self.available_tags.selectedItems() if item is None else [item]
        if not items:
            error_dialog(self, 'No tags selected', 'You must select at least one tag from the list of Available tags.').exec_()
            return
        pos = self.available_tags.verticalScrollBar().value()
        for item in items:
            used = self.db.is_tag_used(unicode_type(item.text())) \
                if self.key is None else \
                self.db.is_item_used_in_multiple(unicode_type(item.text()), label=self.key)
            if used:
                confirms.append(item)
            else:
                deletes.append(item)
        if confirms:
            ct = ', '.join([unicode_type(item.text()) for item in confirms])
            if question_dialog(self, _('Are your sure?'),
                '<p>'+_('The following tags are used by one or more books. '
                    'Are you certain you want to delete them?')+'<br>'+ct):
                deletes += confirms

        for item in deletes:
            if self.key is None:
                self.db.delete_tag(unicode_type(item.text()))
            else:
                bks = self.db.delete_item_from_multiple(unicode_type(item.text()),
                                                        label=self.key)
                self.db.refresh_ids(bks)
            self.available_tags.takeItem(self.available_tags.row(item))
        self.available_tags.verticalScrollBar().setValue(pos)
Esempio n. 2
0
 def _update_drive_info(self, storage, location_code, name=None):
     from calibre.utils.date import isoformat, now
     from calibre.utils.config import from_json, to_json
     import uuid
     f = storage.find_path(self.calibre_file_paths['driveinfo'].split('/'))
     dinfo = {}
     if f is not None:
         try:
             stream = self.get_mtp_file(f)
             dinfo = json.load(stream, object_hook=from_json)
         except:
             prints('Failed to load existing driveinfo.calibre file, with error:')
             traceback.print_exc()
             dinfo = {}
     if dinfo.get('device_store_uuid', None) is None:
         dinfo['device_store_uuid'] = unicode_type(uuid.uuid4())
     if dinfo.get('device_name', None) is None:
         dinfo['device_name'] = self.current_friendly_name
     if name is not None:
         dinfo['device_name'] = name
     dinfo['location_code'] = location_code
     dinfo['last_library_uuid'] = getattr(self, 'current_library_uuid', None)
     dinfo['calibre_version'] = '.'.join([unicode_type(i) for i in numeric_version])
     dinfo['date_last_connected'] = isoformat(now())
     dinfo['mtp_prefix'] = storage.storage_prefix
     raw = json.dumps(dinfo, default=to_json)
     self.put_calibre_file(storage, 'driveinfo', BytesIO(raw), len(raw))
     self.driveinfo[location_code] = dinfo
Esempio n. 3
0
 def chapter_break(self, match):
     chap = match.group('section')
     styles = match.group('styles')
     self.html_preprocess_sections = self.html_preprocess_sections + 1
     self.log.debug("marked " + unicode_type(self.html_preprocess_sections) +
             " section markers based on punctuation. - " + unicode_type(chap))
     return '<'+styles+' style="page-break-before:always">'+chap
Esempio n. 4
0
 def migrate_old_conf(self, old_conf_path):
     from calibre.utils.config import DynamicConfig
     c = DynamicConfig('scheduler')
     for r in c.get('scheduled_recipes', []):
         try:
             self.add_old_recipe(r)
         except:
             continue
     for k in c.keys():
         if k.startswith('recipe_account_info'):
             try:
                 urn = k.replace('recipe_account_info_', '')
                 if urn.startswith('recipe_'):
                     urn = 'builtin:'+urn[7:]
                 else:
                     urn = 'custom:%d'%int(urn)
                 try:
                     username, password = c[k]
                 except:
                     username = password = ''
                 self.set_account_info(urn, unicode_type(username),
                         unicode_type(password))
             except:
                 continue
     del c
     self.write_scheduler_file()
     try:
         os.remove(old_conf_path)
     except:
         pass
Esempio n. 5
0
        def test_mem_leaks(self):
            import gc
            from calibre.utils.mem import get_memory as memory
            m = Matcher(['a'], scorer=CScorer)
            m('a')

            def doit(c):
                m = Matcher([
                    c + 'im/one.gif',
                    c + 'im/two.gif',
                    c + 'text/one.html',
                ],
                            scorer=CScorer)
                m('one')

            start = memory()
            for i in range(10):
                doit(unicode_type(i))
            gc.collect()
            used10 = memory() - start
            start = memory()
            for i in range(100):
                doit(unicode_type(i))
            gc.collect()
            used100 = memory() - start
            if used100 > 0 and used10 > 0:
                self.assertLessEqual(used100, 2 * used10)
Esempio n. 6
0
 def navpoint(parent, np):
     text = np.text
     if not text:
         text = ''
     c[1] += 1
     item_id = 'num_%d'%c[1]
     text = clean_xml_chars(text)
     elem = E.navPoint(
             E.navLabel(E.text(re.sub(r'\s+', ' ', text))),
             E.content(src=unicode_type(np.href)+(('#' + unicode_type(np.fragment))
                 if np.fragment else '')),
             id=item_id,
             playOrder=str(np.play_order)
     )
     au = getattr(np, 'author', None)
     if au:
         au = re.sub(r'\s+', ' ', au)
         elem.append(C.meta(au, name='author'))
     desc = getattr(np, 'description', None)
     if desc:
         desc = re.sub(r'\s+', ' ', desc)
         try:
             elem.append(C.meta(desc, name='description'))
         except ValueError:
             elem.append(C.meta(clean_xml_chars(desc), name='description'))
     idx = getattr(np, 'toc_thumbnail', None)
     if idx:
         elem.append(C.meta(idx, name='toc_thumbnail'))
     parent.append(elem)
     for np2 in np:
         navpoint(elem, np2)
Esempio n. 7
0
    def commit(self, urn=None):
        urn = self.current_urn if urn is None else urn
        if not self.detail_box.isVisible() or urn is None:
            return True

        if self.account.isVisible():
            un, pw = map(unicode_type, (self.username.text(), self.password.text()))
            un, pw = un.strip(), pw.strip()
            if not un and not pw and self.schedule.isChecked():
                if not getattr(self, 'subscription_optional', False):
                    error_dialog(self, _('Need username and password'),
                            _('You must provide a username and/or password to '
                                'use this news source.'), show=True)
                    return False
            if un or pw:
                self.recipe_model.set_account_info(urn, un, pw)
            else:
                self.recipe_model.clear_account_info(urn)

        if self.schedule.isChecked():
            schedule_type, schedule = \
                    self.schedule_stack.currentWidget().schedule
            self.recipe_model.schedule_recipe(urn, schedule_type, schedule)
        else:
            self.recipe_model.un_schedule_recipe(urn)

        add_title_tag = self.add_title_tag.isChecked()
        keep_issues = u'0'
        if self.keep_issues.isEnabled():
            keep_issues = unicode_type(self.keep_issues.value())
        custom_tags = unicode_type(self.custom_tags.text()).strip()
        custom_tags = [x.strip() for x in custom_tags.split(',')]
        self.recipe_model.customize_recipe(urn, add_title_tag, custom_tags, keep_issues)
        return True
Esempio n. 8
0
    def test_winutil(self):
        from calibre.constants import plugins
        from calibre import strftime
        winutil = plugins['winutil'][0]

        def au(x, name):
            self.assertTrue(isinstance(x, unicode_type), name + '() did not return a unicode string')
        for x in winutil.argv():
            au(x, 'argv')
        for x in 'username temp_path locale_name'.split():
            au(getattr(winutil, x)(), x)
        d = winutil.localeconv()
        au(d['thousands_sep'], 'localeconv')
        au(d['decimal_point'], 'localeconv')
        for k, v in iteritems(d):
            au(v, k)
        for k in os.environ.keys():
            au(winutil.getenv(unicode_type(k)), 'getenv-' + k)
        os.environ['XXXTEST'] = 'YYY'
        self.assertEqual(winutil.getenv(u'XXXTEST'), u'YYY')
        del os.environ['XXXTEST']
        self.assertIsNone(winutil.getenv(u'XXXTEST'))
        t = time.localtime()
        fmt = u'%Y%a%b%e%H%M'
        for fmt in (fmt, fmt.encode('ascii')):
            x = strftime(fmt, t)
            au(x, 'strftime')
            self.assertEqual(unicode_type(time.strftime(fmt.replace('%e', '%#d'), t)), x)
Esempio n. 9
0
 def set_email_settings(self, to_set):
     from_ = unicode_type(self.email_from.text()).strip()
     if to_set and not from_:
         error_dialog(self, _('Bad configuration'),
                      _('You must set the From email address')).exec_()
         return False
     username = unicode_type(self.relay_username.text()).strip()
     password = unicode_type(self.relay_password.text()).strip()
     host = unicode_type(self.relay_host.text()).strip()
     enc_method = ('TLS' if self.relay_tls.isChecked() else 'SSL'
             if self.relay_ssl.isChecked() else 'NONE')
     if host:
         # Validate input
         if ((username and not password) or (not username and password)):
             error_dialog(self, _('Bad configuration'),
                         _('You must either set both the username <b>and</b> password for '
                         'the mail server or no username and no password at all.')).exec_()
             return False
         if not (username and password) and not question_dialog(
                 self, _('Are you sure?'),
                 _('No username and password set for mailserver. Most '
                   ' mailservers need a username and password. Are you sure?')):
             return False
     conf = smtp_prefs()
     conf.set('from_', from_)
     conf.set('relay_host', host if host else None)
     conf.set('relay_port', self.relay_port.value())
     conf.set('relay_username', username if username else None)
     conf.set('relay_password', as_hex_unicode(password))
     conf.set('encryption', enc_method)
     return True
Esempio n. 10
0
 def to_html(self):
     '''
     A HTML representation of this object.
     '''
     from calibre.ebooks.metadata import authors_to_string
     from calibre.utils.date import isoformat
     ans = [(_('Title'), unicode_type(self.title))]
     ans += [(_('Author(s)'), (authors_to_string(self.authors) if self.authors else _('Unknown')))]
     ans += [(_('Publisher'), unicode_type(self.publisher))]
     ans += [(_('Producer'), unicode_type(self.book_producer))]
     ans += [(_('Comments'), unicode_type(self.comments))]
     ans += [('ISBN', unicode_type(self.isbn))]
     ans += [(_('Tags'), u', '.join([unicode_type(t) for t in self.tags]))]
     if self.series:
         ans += [(_('Series'), unicode_type(self.series) + ' #%s'%self.format_series_index())]
     ans += [(_('Languages'), u', '.join(self.languages))]
     if self.timestamp is not None:
         ans += [(_('Timestamp'), unicode_type(isoformat(self.timestamp, as_utc=False, sep=' ')))]
     if self.pubdate is not None:
         ans += [(_('Published'), unicode_type(isoformat(self.pubdate, as_utc=False, sep=' ')))]
     if self.rights is not None:
         ans += [(_('Rights'), unicode_type(self.rights))]
     for key in self.custom_field_keys():
         val = self.get(key, None)
         if val:
             (name, val) = self.format_field(key)
             ans += [(name, val)]
     for i, x in enumerate(ans):
         ans[i] = u'<tr><td><b>%s</b></td><td>%s</td></tr>'%x
     return u'<table>%s</table>'%u'\n'.join(ans)
Esempio n. 11
0
 def test_workers(self):
     ' Test worker semantics '
     with TestServer(lambda data:(data.path[0] + data.read()), worker_count=3) as server:
         self.ae(3, sum(int(w.is_alive()) for w in server.loop.pool.workers))
         server.loop.stop()
         server.join()
         self.ae(0, sum(int(w.is_alive()) for w in server.loop.pool.workers))
     # Test shutdown with hung worker
     block = Event()
     with TestServer(lambda data:block.wait(), worker_count=3, shutdown_timeout=0.1, timeout=0.01) as server:
         pool = server.loop.pool
         self.ae(3, sum(int(w.is_alive()) for w in pool.workers))
         conn = server.connect()
         conn.request('GET', '/')
         with self.assertRaises(socket.timeout):
             res = conn.getresponse()
             if unicode_type(res.status) == unicode_type(http_client.REQUEST_TIMEOUT):
                 raise socket.timeout('Timeout')
             raise Exception('Got unexpected response: code: %s %s headers: %r data: %r' % (
                 res.status, res.reason, res.getheaders(), res.read()))
         self.ae(pool.busy, 1)
         server.loop.log.filter_level = server.loop.log.ERROR
         server.loop.stop()
         server.join()
         self.ae(1, sum(int(w.is_alive()) for w in pool.workers))
Esempio n. 12
0
    def gst_save_clicked(self):
        idx = self.gst_names.currentIndex()
        name = icu_lower(unicode_type(self.gst_names.currentText()))
        if not name:
            return error_dialog(self.gui, _('Grouped search terms'),
                                _('The search term cannot be blank'),
                                show=True)
        if idx != 0:
            orig_name = unicode_type(self.gst_names.itemData(idx) or '')
        else:
            orig_name = ''
        if name != orig_name:
            if name in self.db.field_metadata.get_search_terms() and \
                    name not in self.orig_gst_keys:
                return error_dialog(self.gui, _('Grouped search terms'),
                    _('That name is already used for a column or grouped search term'),
                    show=True)
            if name in [icu_lower(p) for p in self.db.prefs.get('user_categories', {})]:
                return error_dialog(self.gui, _('Grouped search terms'),
                    _('That name is already used for User category'),
                    show=True)

        val = [v.strip() for v in unicode_type(self.gst_value.text()).split(',') if v.strip()]
        if not val:
            return error_dialog(self.gui, _('Grouped search terms'),
                _('The value box cannot be empty'), show=True)

        if orig_name and name != orig_name:
            del self.gst[orig_name]
        self.gst_changed = True
        self.gst[name] = val
        self.fill_gst_box(select=name)
        self.set_similar_fields(initial=False)
        self.changed_signal.emit()
Esempio n. 13
0
    def box_search_string(self):
        mk = self.matchkind.currentIndex()
        if mk == CONTAINS_MATCH:
            self.mc = ''
        elif mk == EQUALS_MATCH:
            self.mc = '='
        else:
            self.mc = '~'

        ans = []
        self.box_last_values = {}
        title = unicode_type(self.title_box.text()).strip()
        if title:
            ans.append('title:"' + self.mc + title + '"')
        author = unicode_type(self.author_box.text()).strip()
        if author:
            ans.append('author:"' + self.mc + author + '"')
        price = unicode_type(self.price_box.text()).strip()
        if price:
            ans.append('price:"' + self.mc + price + '"')
        format = unicode_type(self.format_box.text()).strip()
        if format:
            ans.append('format:"' + self.mc + format + '"')
        drm = '' if self.drm_combo.currentIndex() == 0 else 'true' if self.drm_combo.currentIndex() == 1 else 'false'
        if drm:
            ans.append('drm:' + drm)
        download = '' if self.download_combo.currentIndex() == 0 else 'true' if self.download_combo.currentIndex() == 1 else 'false'
        if download:
            ans.append('download:' + download)
        affiliate = '' if self.affiliate_combo.currentIndex() == 0 else 'true' if self.affiliate_combo.currentIndex() == 1 else 'false'
        if affiliate:
            ans.append('affiliate:' + affiliate)
        if ans:
            return ' and '.join(ans)
        return ''
Esempio n. 14
0
    def initialize(self, shortcut, all_shortcuts):
        self.header.setText('<b>%s: %s</b>'%(_('Customize'), shortcut['name']))
        self.all_shortcuts = all_shortcuts
        self.shortcut = shortcut

        self.default_keys = [QKeySequence(k, QKeySequence.PortableText) for k
                in shortcut['default_keys']]
        self.current_keys = list(shortcut['keys'])
        default = ', '.join([unicode_type(k.toString(k.NativeText)) for k in
                    self.default_keys])
        if not default:
            default = _('None')
        current = ', '.join([unicode_type(k.toString(k.NativeText)) for k in
                    self.current_keys])
        if not current:
            current = _('None')

        self.use_default.setText(_('&Default: %(deflt)s [Currently not conflicting: %(curr)s]')%
                dict(deflt=default, curr=current))

        if shortcut['set_to_default']:
            self.use_default.setChecked(True)
        else:
            self.use_custom.setChecked(True)
            for key, which in zip(self.current_keys, [1,2]):
                button = getattr(self, 'button%d'%which)
                button.setText(key.toString(key.NativeText))
Esempio n. 15
0
 def add_recipient(self):
     to = unicode_type(self.address.text()).strip()
     if not to:
         return error_dialog(
             self, _('Need address'), _('You must specify an address'), show=True)
     formats = ','.join([x.strip().upper() for x in unicode_type(self.formats.text()).strip().split(',') if x.strip()])
     if not formats:
         return error_dialog(
             self, _('Need formats'), _('You must specify at least one format to send'), show=True)
     opts = email_config().parse()
     if to in opts.accounts:
         return error_dialog(
             self, _('Already exists'), _('The recipient %s already exists') % to, show=True)
     acc = opts.accounts
     acc[to] = [formats, False, False]
     c = email_config()
     c.set('accounts', acc)
     alias = unicode_type(self.alias.text()).strip()
     if alias:
         opts.aliases[to] = alias
         c.set('aliases', opts.aliases)
     subject = unicode_type(self.subject.text()).strip()
     if subject:
         opts.subjects[to] = subject
         c.set('subjects', opts.subjects)
     self.create_item(alias or to, to, checked=True)
Esempio n. 16
0
 def request_split(self, loc, totals):
     actions['split-in-preview'].setChecked(False)
     loc, totals = json.loads(unicode_type(loc)), json.loads(unicode_type(totals))
     if not loc or not totals:
         return error_dialog(self.view(), _('Invalid location'),
                             _('Cannot split on the body tag'), show=True)
     self.split_requested.emit(loc, totals)
Esempio n. 17
0
    def default_cover(self):
        '''
        Create a generic cover for books that dont have a cover
        '''
        if self.no_default_cover:
            return None
        self.log('Generating default cover')
        m = self.oeb.metadata
        title = unicode_type(m.title[0])
        authors = [unicode_type(x) for x in m.creator if x.role == 'aut']
        try:
            from calibre.ebooks.covers import create_cover
            series = series_index = None
            if m.series:
                try:
                    series, series_index = unicode_type(m.series[0]), m.series_index[0]
                except IndexError:
                    pass
            img_data = create_cover(title, authors, series, series_index)
            id, href = self.oeb.manifest.generate('cover',
                    u'cover_image.jpg')
            item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0],
                        data=img_data)
            m.clear('cover')
            m.add('cover', item.id)

            return item.href
        except:
            self.log.exception('Failed to generate default cover')
        return None
Esempio n. 18
0
def parse_ncx(container, ncx_name):
    root = container.parsed(ncx_name)
    toc_root = TOC()
    navmaps = root.xpath('//*[calibre:lower-case(local-name()) = "navmap"]')
    if navmaps:
        process_ncx_node(container, navmaps[0], toc_root, ncx_name)
    toc_root.lang = toc_root.uid = None
    for attr, val in iteritems(root.attrib):
        if attr.endswith('lang'):
            toc_root.lang = unicode_type(val)
            break
    for uid in root.xpath('//*[calibre:lower-case(local-name()) = "meta" and @name="dtb:uid"]/@content'):
        if uid:
            toc_root.uid = unicode_type(uid)
            break
    for pl in root.xpath('//*[calibre:lower-case(local-name()) = "pagelist"]'):
        for pt in pl.xpath('descendant::*[calibre:lower-case(local-name()) = "pagetarget"]'):
            pagenum = pt.get('value')
            if pagenum:
                href = pt.xpath('descendant::*[calibre:lower-case(local-name()) = "content"]/@src')
                if href:
                    dest = container.href_to_name(href[0], base=ncx_name)
                    frag = urlparse(href[0]).fragment or None
                    toc_root.page_list.append({'dest': dest, 'pagenum': pagenum, 'frag': frag})
    return toc_root
Esempio n. 19
0
    def get_cover(self):
        from calibre.ebooks.oeb.base import OEB_RASTER_IMAGES

        cover_href = None

        # Get the raster cover if it's available.
        if self.oeb_book.metadata.cover and unicode_type(self.oeb_book.metadata.cover[0]) in self.oeb_book.manifest.ids:
            id = unicode_type(self.oeb_book.metadata.cover[0])
            cover_item = self.oeb_book.manifest.ids[id]
            if cover_item.media_type in OEB_RASTER_IMAGES:
                cover_href = cover_item.href
        else:
            # Figure out if we have a title page or a cover page
            page_name = ''
            if 'titlepage' in self.oeb_book.guide:
                page_name = 'titlepage'
            elif 'cover' in self.oeb_book.guide:
                page_name = 'cover'

            if page_name:
                cover_item = self.oeb_book.manifest.hrefs[self.oeb_book.guide[page_name].href]
                # Get the first image in the page
                for img in cover_item.xpath('//img'):
                    cover_href = cover_item.abshref(img.get('src'))
                    break

        if cover_href:
            # Only write the image tag if it is in the manifest.
            if cover_href in self.oeb_book.manifest.hrefs.keys():
                if cover_href not in self.image_hrefs.keys():
                    self.image_hrefs[cover_href] = '_%s.jpg' % len(self.image_hrefs.keys())
            return u'<coverpage><image xlink:href="#%s" /></coverpage>' % self.image_hrefs[cover_href]

        return u''
Esempio n. 20
0
def main(args=sys.argv):
    parser = option_parser()
    opts, args = parser.parse_args(args)
    if len(args) < 2:
        parser.print_help()
        prints(_('No file specified'), file=sys.stderr)
        return 1
    path = args[1]
    stream_type = os.path.splitext(path)[1].replace('.', '').lower()

    trying_to_set = False
    for pref in config().option_set.preferences:
        if pref.name in ('to_opf', 'get_cover'):
            continue
        if getattr(opts, pref.name) is not None:
            trying_to_set = True
            break
    with open(path, 'rb') as stream:
        mi = get_metadata(stream, stream_type, force_read_metadata=True)
    if trying_to_set:
        prints(_('Original metadata')+'::')
    metadata = unicode_type(mi)
    if trying_to_set:
        metadata = '\t'+'\n\t'.join(metadata.split('\n'))
    prints(metadata, safe_encode=True)

    if trying_to_set:
        with open(path, 'r+b') as stream:
            do_set_metadata(opts, mi, stream, stream_type)
            stream.seek(0)
            stream.flush()
            lrf = None
            if stream_type == 'lrf':
                if opts.lrf_bookid is not None:
                    lrf = LRFMetaFile(stream)
                    lrf.book_id = opts.lrf_bookid
            mi = get_metadata(stream, stream_type, force_read_metadata=True)
        prints('\n' + _('Changed metadata') + '::')
        metadata = unicode_type(mi)
        metadata = '\t'+'\n\t'.join(metadata.split('\n'))
        prints(metadata, safe_encode=True)
        if lrf is not None:
            prints('\tBookID:', lrf.book_id)

    if opts.to_opf is not None:
        from calibre.ebooks.metadata.opf2 import OPFCreator
        opf = OPFCreator(getcwd(), mi)
        with open(opts.to_opf, 'wb') as f:
            opf.render(f)
        prints(_('OPF created in'), opts.to_opf)

    if opts.get_cover is not None:
        if mi.cover_data and mi.cover_data[1]:
            with open(opts.get_cover, 'wb') as f:
                f.write(mi.cover_data[1])
                prints(_('Cover saved to'), f.name)
        else:
            prints(_('No cover found'), file=sys.stderr)

    return 0
Esempio n. 21
0
 def save_settings(cls, config_widget):
     proxy = cls._configProxy()
     proxy['format_map'] = config_widget.format_map()
     if cls.SUPPORTS_SUB_DIRS:
         proxy['use_subdirs'] = config_widget.use_subdirs()
     if not cls.MUST_READ_METADATA:
         proxy['read_metadata'] = config_widget.read_metadata()
     if cls.SUPPORTS_USE_AUTHOR_SORT:
         proxy['use_author_sort'] = config_widget.use_author_sort()
     if cls.EXTRA_CUSTOMIZATION_MESSAGE:
         if isinstance(cls.EXTRA_CUSTOMIZATION_MESSAGE, list):
             ec = []
             for i in range(0, len(cls.EXTRA_CUSTOMIZATION_MESSAGE)):
                 if config_widget.opt_extra_customization[i] is None:
                     ec.append(None)
                     continue
                 if hasattr(config_widget.opt_extra_customization[i], 'isChecked'):
                     ec.append(config_widget.opt_extra_customization[i].isChecked())
                 elif hasattr(config_widget.opt_extra_customization[i], 'currentText'):
                     ec.append(unicode_type(config_widget.opt_extra_customization[i].currentText()).strip())
                 else:
                     ec.append(unicode_type(config_widget.opt_extra_customization[i].text()).strip())
         else:
             ec = unicode_type(config_widget.opt_extra_customization.text()).strip()
             if not ec:
                 ec = None
         proxy['extra_customization'] = ec
     st = unicode_type(config_widget.opt_save_template.text())
     proxy['save_template'] = st
Esempio n. 22
0
    def options(self):

        # Save the currently activated fields
        fields = []
        for x in range(self.db_fields.count()):
            item = self.db_fields.item(x)
            if item.isSelected():
                fields.append(unicode_type(item.text()))
        gprefs.set(self.name+'_db_fields', fields)

        # Dictionary currently activated fields
        if len(self.db_fields.selectedItems()):
            opts_dict = {'fields':[unicode_type(i.text()) for i in self.db_fields.selectedItems()]}
        else:
            opts_dict = {'fields':['all']}

        # Save/return the current options
        # bib_cit stores as text
        # 'bibfile_enc','bibfile_enctag' stores as int (Indexes)
        for opt in self.OPTION_FIELDS:
            if opt[0] in ['bibfile_enc', 'bibfile_enctag', 'bib_entry']:
                opt_value = getattr(self,opt[0]).currentIndex()
            elif opt[0] in ['impcit', 'addfiles'] :
                opt_value = getattr(self, opt[0]).isChecked()
            else :
                opt_value = unicode_type(getattr(self, opt[0]).text())
            gprefs.set(self.name + '_' + opt[0], opt_value)

            opts_dict[opt[0]] = opt_value

        return opts_dict
Esempio n. 23
0
 def all_in_marked(self, pat, template=None):
     if self.current_search_mark is None:
         return 0
     c = self.current_search_mark.cursor
     raw = unicode_type(c.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0')
     if template is None:
         count = len(pat.findall(raw))
     else:
         from calibre.gui2.tweak_book.function_replace import Function
         repl_is_func = isinstance(template, Function)
         if repl_is_func:
             template.init_env()
         raw, count = pat.subn(template, raw)
         if repl_is_func:
             from calibre.gui2.tweak_book.search import show_function_debug_output
             if getattr(template.func, 'append_final_output_to_marked', False):
                 retval = template.end()
                 if retval:
                     raw += unicode_type(retval)
             else:
                 template.end()
             show_function_debug_output(template)
         if count > 0:
             start_pos = min(c.anchor(), c.position())
             c.insertText(raw)
             end_pos = max(c.anchor(), c.position())
             c.setPosition(start_pos), c.setPosition(end_pos, c.KeepAnchor)
             self.update_extra_selections()
     return count
Esempio n. 24
0
    def init_search_box_mixin(self):
        self.search.initialize('main_search_history', colorize=True,
                help_text=_('Search (For advanced search click the gear icon to the left)'))
        self.search.cleared.connect(self.search_box_cleared)
        # Queued so that search.current_text will be correct
        self.search.changed.connect(self.search_box_changed,
                type=Qt.QueuedConnection)
        self.search.focus_to_library.connect(self.focus_to_library)
        self.advanced_search_toggle_action.triggered.connect(self.do_advanced_search)

        self.search.clear()
        self.search.setMaximumWidth(self.width()-150)
        self.action_focus_search = QAction(self)
        shortcuts = list(
                map(lambda x:unicode_type(x.toString(QKeySequence.PortableText)),
                QKeySequence.keyBindings(QKeySequence.Find)))
        shortcuts += ['/', 'Alt+S']
        self.keyboard.register_shortcut('start search', _('Start search'),
                default_keys=shortcuts, action=self.action_focus_search)
        self.action_focus_search.triggered.connect(self.focus_search_box)
        self.addAction(self.action_focus_search)
        self.search.setStatusTip(re.sub(r'<\w+>', ' ',
            unicode_type(self.search.toolTip())))
        self.set_highlight_only_button_icon()
        self.highlight_only_button.clicked.connect(self.highlight_only_clicked)
        tt = _('Enable or disable search highlighting.') + '<br><br>'
        tt += config.help('highlight_search_matches')
        self.highlight_only_button.setToolTip(tt)
        self.highlight_only_action = ac = QAction(self)
        self.addAction(ac), ac.triggered.connect(self.highlight_only_clicked)
        self.keyboard.register_shortcut('highlight search results', _('Highlight search results'), action=self.highlight_only_action)
Esempio n. 25
0
    def create_cover_markup(self, img, preserve_aspect_ratio, width, height):
        self.count += 1
        makeelement, namespaces = self.document_relationships.namespace.makeelement, self.document_relationships.namespace.namespaces
        if preserve_aspect_ratio:
            if img.width >= img.height:
                ar = img.height / img.width
                height = ar * width
            else:
                ar = img.width / img.height
                width = ar * height

        root = etree.Element('root', nsmap=namespaces)
        ans = makeelement(root, 'w:drawing', append=False)
        parent = makeelement(ans, 'wp:anchor', **{'dist'+edge:'0' for edge in 'LRTB'})
        parent.set('simplePos', '0'), parent.set('relativeHeight', '1'), parent.set('behindDoc',"0"), parent.set('locked', "0")
        parent.set('layoutInCell', "1"), parent.set('allowOverlap', '1')
        makeelement(parent, 'wp:simplePos', x='0', y='0')
        makeelement(makeelement(parent, 'wp:positionH', relativeFrom='page'), 'wp:align').text = 'center'
        makeelement(makeelement(parent, 'wp:positionV', relativeFrom='page'), 'wp:align').text = 'center'
        width, height = map(pt_to_emu, (width, height))
        makeelement(parent, 'wp:extent', cx=unicode_type(width), cy=unicode_type(height))
        makeelement(parent, 'wp:effectExtent', l='0', r='0', t='0', b='0')
        makeelement(parent, 'wp:wrapTopAndBottom')
        self.create_docx_image_markup(parent, 'cover.jpg', _('Cover'), img.rid, width, height)
        return ans
Esempio n. 26
0
 def save_search_button_clicked(self):
     from calibre.gui2.ui import get_gui
     db = get_gui().current_db
     name = unicode_type(self.currentText())
     if not name.strip():
         name = unicode_type(self.search_box.text()).replace('"', '')
     name = name.replace('\\', '')
     if not name:
         error_dialog(self, _('Create saved search'),
                      _('Invalid saved search name. '
                        'It must contain at least one letter or number'), show=True)
         return
     if not self.search_box.text():
         error_dialog(self, _('Create saved search'),
                      _('There is no search to save'), show=True)
         return
     db.saved_search_delete(name)
     db.saved_search_add(name, unicode_type(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.
     self.clear()
     self.setCurrentIndex(self.findText(name))
     self.saved_search_selected(name)
     self.changed.emit()
Esempio n. 27
0
    def get_cookies(self):
        '''
        Writes QNetworkCookies to Mozilla cookie .txt file.

        :return: The file path to the cookie file.
        '''
        cf = PersistentTemporaryFile(suffix='.txt')

        cf.write('# Netscape HTTP Cookie File\n\n')

        for c in self.page().networkAccessManager().cookieJar().allCookies():
            cookie = []
            domain = unicode_type(c.domain())

            cookie.append(domain)
            cookie.append('TRUE' if domain.startswith('.') else 'FALSE')
            cookie.append(unicode_type(c.path()))
            cookie.append('TRUE' if c.isSecure() else 'FALSE')
            cookie.append(unicode_type(c.expirationDate().toTime_t()))
            cookie.append(unicode_type(c.name()))
            cookie.append(unicode_type(c.value()))

            cf.write('\t'.join(cookie))
            cf.write('\n')

        cf.close()
        return cf.name
Esempio n. 28
0
 def copy_to_clipboard(self, *args):
     QApplication.clipboard().setText(
             'calibre, version %s\n%s: %s\n\n%s' %
             (__version__, unicode_type(self.windowTitle()),
                 unicode_type(self.msg_label.text()),
                 unicode_type(self.det_msg.toPlainText())))
     self.copy_button.setText(_('Copied'))
Esempio n. 29
0
 def rule(self):
     folder = unicode_type(self.folder.text()).strip()
     if folder:
         return (
             unicode_type(self.fmt.itemData(self.fmt.currentIndex()) or ''),
             folder
             )
     return None
Esempio n. 30
0
 def emit_navigate(self, *args):
     item = self.view.currentItem()
     if item is not None:
         dest = unicode_type(item.data(0, DEST_ROLE) or '')
         frag = unicode_type(item.data(0, FRAG_ROLE) or '')
         if not frag:
             frag = TOP
         self.navigate_requested.emit(dest, frag)
Esempio n. 31
0
def category(ctx, rd, encoded_name, library_id):
    '''
    Return a dictionary describing the category specified by name. The

    Optional: ?num=100&offset=0&sort=name&sort_order=asc

    The dictionary looks like::

        {
            'category_name': Category display name,
            'base_url': Base URL for this category,
            'total_num': Total numberof items in this category,
            'offset': The offset for the items returned in this result,
            'num': The number of items returned in this result,
            'sort': How the returned items are sorted,
            'sort_order': asc or desc
            'subcategories': List of sub categories of this category.
            'items': List of items in this category,
        }

    Each subcategory is a dictionary of the same form as those returned by
    /ajax/categories

    Each  item is a dictionary of the form::

        {
            'name': Display name,
            'average_rating': Average rating for books in this item,
            'count': Number of books in this item,
            'url': URL to get list of books in this item,
            'has_children': If True this item contains sub categories, look
            for an entry corresponding to this item in subcategories int he
            main dictionary,
        }

    :param sort: How to sort the returned items. Choices are: name, rating,
                    popularity
    :param sort_order: asc or desc

    To learn how to create subcategories see
    https://manual.calibre-ebook.com/sub_groups.html
    '''

    db = get_db(ctx, rd, library_id)
    with db.safe_read_lock:
        num, offset = get_pagination(rd.query)
        sort, sort_order = rd.query.get('sort'), rd.query.get('sort_order')
        sort = ensure_val(sort, 'name', 'rating', 'popularity')
        sort_order = ensure_val(sort_order, 'asc', 'desc')
        try:
            dname = decode_name(encoded_name)
        except:
            raise HTTPNotFound('Invalid encoding of category name %r' %
                               encoded_name)
        base_url = ctx.url_for(globals()['category'],
                               encoded_name=encoded_name,
                               library_id=db.server_library_id)

        if dname in ('newest', 'allbooks'):
            sort, sort_order = 'timestamp', 'desc'
            rd.query['sort'], rd.query['sort_order'] = sort, sort_order
            return books_in(ctx, rd, encoded_name, encode_name('0'),
                            library_id)

        fm = db.field_metadata
        categories = ctx.get_categories(rd, db)
        hierarchical_categories = db.pref('categories_using_hierarchy', ())

        subcategory = dname
        toplevel = subcategory.partition('.')[0]
        if toplevel == subcategory:
            subcategory = None
        if toplevel not in categories or toplevel not in fm:
            raise HTTPNotFound('Category %r not found' % toplevel)

        # Find items and sub categories
        subcategories = []
        meta = fm[toplevel]
        item_names = {}
        children = set()

        if meta['kind'] == 'user':
            fullname = ((toplevel + '.' +
                         subcategory) if subcategory is not None else toplevel)
            try:
                # User categories cannot be applied to books, so this is the
                # complete set of items, no need to consider sub categories
                items = categories[fullname]
            except:
                raise HTTPNotFound('User category %r not found' % fullname)

            parts = fullname.split('.')
            for candidate in categories:
                cparts = candidate.split('.')
                if len(cparts) == len(parts) + 1 and cparts[:-1] == parts:
                    subcategories.append({
                        'name': cparts[-1],
                        'url': candidate,
                        'icon': category_icon(toplevel, meta)
                    })

            category_name = toplevel[1:].split('.')
            # When browsing by user categories we ignore hierarchical normal
            # columns, so children can be empty

        elif toplevel in hierarchical_categories:
            items = []

            category_names = [
                x.original_name.split('.') for x in categories[toplevel]
                if '.' in x.original_name
            ]

            if subcategory is None:
                children = set(x[0] for x in category_names)
                category_name = [meta['name']]
                items = [
                    x for x in categories[toplevel]
                    if '.' not in x.original_name
                ]
            else:
                subcategory_parts = subcategory.split('.')[1:]
                category_name = [meta['name']] + subcategory_parts

                lsp = len(subcategory_parts)
                children = set(
                    '.'.join(x) for x in category_names
                    if len(x) == lsp + 1 and x[:lsp] == subcategory_parts)
                items = [
                    x for x in categories[toplevel]
                    if x.original_name in children
                ]
                item_names = {
                    x: x.original_name.rpartition('.')[-1]
                    for x in items
                }
                # Only mark the subcategories that have children themselves as
                # subcategories
                children = set(
                    '.'.join(x[:lsp + 1]) for x in category_names
                    if len(x) > lsp + 1 and x[:lsp] == subcategory_parts)
            subcategories = [{
                'name': x.rpartition('.')[-1],
                'url': toplevel + '.' + x,
                'icon': category_icon(toplevel, meta)
            } for x in children]
        else:
            items = categories[toplevel]
            category_name = meta['name']

        for x in subcategories:
            x['url'] = ctx.url_for(globals()['category'],
                                   encoded_name=encode_name(x['url']),
                                   library_id=db.server_library_id)
            x['icon'] = ctx.url_for(get_icon, which=x['icon'])
            x['is_category'] = True

        sort_keygen = {
            'name': lambda x: sort_key(x.sort if x.sort else x.original_name),
            'popularity': lambda x: x.count,
            'rating': lambda x: x.avg_rating
        }
        items.sort(key=sort_keygen[sort], reverse=sort_order == 'desc')
        total_num = len(items)
        items = items[offset:offset + num]
        items = [{
            'name':
            item_names.get(x, x.original_name),
            'average_rating':
            x.avg_rating,
            'count':
            x.count,
            'url':
            ctx.url_for(
                books_in,
                encoded_category=encode_name(
                    x.category if x.category else toplevel),
                encoded_item=encode_name(
                    x.original_name if x.id is None else unicode_type(x.id)),
                library_id=db.server_library_id),
            'has_children':
            x.original_name in children,
        } for x in items]

        return {
            'category_name': category_name,
            'base_url': base_url,
            'total_num': total_num,
            'offset': offset,
            'num': len(items),
            'sort': sort,
            'sort_order': sort_order,
            'subcategories': subcategories,
            'items': items,
        }
Esempio n. 32
0
 def color_to_clipboard(self):
     app = QApplication.instance()
     c = app.clipboard()
     c.setText(unicode_type(self.color_name.color))
Esempio n. 33
0
 def setEditorData(self, editor, index):
     name = unicode_type(index.data(Qt.DisplayRole) or '')
     editor.setText(name)
     editor.lineEdit().selectAll()
Esempio n. 34
0
 def value(self):
     ans = [x.strip() for x in unicode_type(self.t.text()).strip().split(',')]
     return [x for x in ans if x]
Esempio n. 35
0
 def format_map(self):
     return [unicode_type(self.f.item(i).data(Qt.ItemDataRole.UserRole) or '') for i in
             range(self.f.count()) if self.f.item(i).checkState()==Qt.CheckState.Checked]
Esempio n. 36
0
    def __init__(self, parent, dbspec, ids, db):
        import re
        from calibre import prints as info
        from PyQt5.uic import compileUi

        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.dbspec, self.ids = dbspec, ids

        # Display the number of books we've been passed
        self.count.setText(unicode_type(self.count.text()).format(len(ids)))

        # Display the last-used title
        self.title.setText(
            dynamic.get('catalog_last_used_title', _('My books')))

        self.fmts, self.widgets = [], []

        for plugin in catalog_plugins():
            if plugin.name in config['disabled_plugins']:
                continue

            name = plugin.name.lower().replace(' ', '_')
            if getattr(plugin, 'plugin_path', None) is None:
                try:
                    catalog_widget = importlib.import_module(
                        'calibre.gui2.catalog.' + name)
                    pw = catalog_widget.PluginWidget()
                    pw.parent_ref = weakref.ref(self)
                    pw.initialize(name, db)
                    pw.ICON = I('forward.png')
                    self.widgets.append(pw)
                    [
                        self.fmts.append(
                            [file_type.upper(), pw.sync_enabled, pw])
                        for file_type in plugin.file_types
                    ]
                except ImportError:
                    info("ImportError initializing %s" % name)
                    continue
            else:
                # Load dynamic tab
                form = os.path.join(plugin.resources_path, '%s.ui' % name)
                klass = os.path.join(plugin.resources_path, '%s.py' % name)
                compiled_form = os.path.join(plugin.resources_path,
                                             '%s_ui.py' % name)

                if os.path.exists(form) and os.path.exists(klass):
                    # info("Adding widget for user-installed Catalog plugin %s" % plugin.name)

                    # Compile the .ui form provided in plugin.zip
                    if not os.path.exists(compiled_form):
                        from polyglot.io import PolyglotStringIO
                        # info('\tCompiling form', form)
                        buf = PolyglotStringIO()
                        compileUi(form, buf)
                        dat = buf.getvalue()
                        dat = re.compile(
                            r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?<!\\)",.+?\)',
                            re.DOTALL).sub(r'_("\1")', dat)
                        open(compiled_form, 'wb').write(dat.encode('utf-8'))

                    # Import the dynamic PluginWidget() from .py file provided in plugin.zip
                    try:
                        sys.path.insert(0, plugin.resources_path)
                        catalog_widget = importlib.import_module(name)
                        pw = catalog_widget.PluginWidget()
                        pw.initialize(name)
                        pw.ICON = I('forward.png')
                        self.widgets.append(pw)
                        [
                            self.fmts.append(
                                [file_type.upper(), pw.sync_enabled, pw])
                            for file_type in plugin.file_types
                        ]
                    except ImportError:
                        info("ImportError with %s" % name)
                        continue
                    finally:
                        sys.path.remove(plugin.resources_path)

                else:
                    info("No dynamic tab resources found for %s" % name)

        self.widgets = sorted(self.widgets, key=lambda x: x.TITLE)

        # Generate a sorted list of installed catalog formats/sync_enabled pairs
        fmts = sorted((x[0] for x in self.fmts))

        self.sync_enabled_formats = []
        for fmt in self.fmts:
            if fmt[1]:
                self.sync_enabled_formats.append(fmt[0])

        # Callbacks when format, title changes
        self.format.currentIndexChanged.connect(self.format_changed)
        self.format.currentIndexChanged.connect(self.settings_changed)
        self.title.editingFinished.connect(self.settings_changed)

        # Add the installed catalog format list to the format QComboBox
        self.format.blockSignals(True)
        self.format.addItems(fmts)

        pref = dynamic.get('catalog_preferred_format', 'CSV')
        idx = self.format.findText(pref)
        if idx > -1:
            self.format.setCurrentIndex(idx)
        self.format.blockSignals(False)

        if self.sync.isEnabled():
            self.sync.setChecked(dynamic.get('catalog_sync_to_device', True))
        self.add_to_library.setChecked(
            dynamic.get('catalog_add_to_library', True))

        self.format.currentIndexChanged.connect(self.show_plugin_tab)
        self.buttonBox.button(self.buttonBox.Apply).clicked.connect(self.apply)
        self.buttonBox.button(self.buttonBox.Help).clicked.connect(self.help)
        self.show_plugin_tab(None)

        geom = dynamic.get('catalog_window_geom', None)
        if geom is not None:
            self.restoreGeometry(bytes(geom))
        else:
            self.resize(self.sizeHint())
        d = QCoreApplication.instance().desktop()
        g = d.availableGeometry(d.screenNumber(self))
        self.setMaximumWidth(g.width() - 50)
        self.setMaximumHeight(g.height() - 50)
Esempio n. 37
0
 def completion_selected(self, text):
     before_text, after_text = self.get_completed_text(unicode_type(text))
     self.setText(before_text + after_text)
     self.setCursorPosition(len(before_text))
     self.item_selected.emit(text)
Esempio n. 38
0
 def get_value_handler(self, g):
     if g is not self.opt_markdown_extensions:
         return Widget.get_value_handler(self, g)
     return ', '.join(
         unicode_type(i.data(Qt.UserRole) or '')
         for i in itervalues(self.md_map) if i.checkState())
Esempio n. 39
0
    def write_book(self, book_id, mi, components, fmts):
        base_path = os.path.join(self.root, *components)
        base_dir = os.path.dirname(base_path)
        if self.opts.formats and self.opts.formats != 'all':
            asked_formats = {
                x.lower().strip()
                for x in self.opts.formats.split(',')
            }
            fmts = asked_formats.intersection(fmts)
            if not fmts:
                self.errors[book_id].append(
                    ('critical', _('Requested formats not available')))
                return

        if not fmts and not self.opts.write_opf and not self.opts.save_cover:
            return

        # On windows python incorrectly raises an access denied exception
        # when trying to create the root of a drive, like C:\
        if os.path.dirname(base_dir) != base_dir:
            try:
                os.makedirs(base_dir)
            except EnvironmentError as err:
                if err.errno != errno.EEXIST:
                    raise

        if self.opts.update_metadata:
            d = {}
            d['last_modified'] = mi.last_modified.isoformat()

        cdata = self.db.cover(book_id)
        mi.cover, mi.cover_data = None, (None, None)

        if cdata:
            fname = None
            if self.opts.save_cover:
                fname = base_path + os.extsep + 'jpg'
                mi.cover = os.path.basename(fname)
            elif self.opts.update_metadata:
                fname = os.path.join(self.tdir, '%d.jpg' % book_id)

            if fname:
                with lopen(fname, 'wb') as f:
                    f.write(cdata)
                if self.opts.update_metadata:
                    d['cover'] = fname

        fname = None
        if self.opts.write_opf:
            fname = base_path + os.extsep + 'opf'
        elif self.opts.update_metadata:
            fname = os.path.join(self.tdir, '%d.opf' % book_id)
        if fname:
            opf = metadata_to_opf(mi)
            with lopen(fname, 'wb') as f:
                f.write(opf)
            if self.opts.update_metadata:
                d['opf'] = fname
        mi.cover, mi.cover_data = None, (None, None)
        if self.opts.update_metadata:
            d['fmts'] = []
        for fmt in fmts:
            try:
                fmtpath = self.write_fmt(book_id, fmt, base_path)
                if fmtpath and self.opts.update_metadata and can_set_metadata(
                        fmt):
                    d['fmts'].append(fmtpath)
            except Exception:
                self.errors[book_id].append(
                    ('fmt', (fmt, traceback.format_exc())))
        if self.opts.update_metadata:
            if d['fmts']:
                try:
                    self.pool(book_id, 'calibre.library.save_to_disk',
                              'update_serialized_metadata', d)
                except Failure as err:
                    error_dialog(
                        self.pd,
                        _('Critical failure'),
                        _('Could not save books to disk, click "Show details" for more information'
                          ),
                        det_msg=unicode_type(err.failure_message) + '\n' +
                        unicode_type(err.details),
                        show=True)
                    self.pd.canceled = True
            else:
                self.pd.value += 1
                self.pd.msg = self.book_id_data(book_id).title
 def write(self, *args):
     for a in args:
         self.__output.append(unicode_type(a))
Esempio n. 41
0
    def create_menubar(self):
        if isosx:
            p, q = self.create_application_menubar()
            q.triggered.connect(self.action_quit.trigger)
            p.triggered.connect(self.action_preferences.trigger)
        f = factory(app_id='com.calibre-ebook.EditBook-%d' % os.getpid())
        b = f.create_window_menubar(self)

        f = b.addMenu(_('&File'))
        f.addAction(self.action_new_file)
        f.addAction(self.action_import_files)
        f.addSeparator()
        f.addAction(self.action_open_book)
        f.addAction(self.action_new_book)
        f.addAction(self.action_import_book)
        f.addAction(self.action_open_book_folder)
        self.recent_books_menu = f.addMenu(_('&Recently opened books'))
        self.update_recent_books()
        f.addSeparator()
        f.addAction(self.action_save)
        f.addAction(self.action_save_copy)
        f.addSeparator()
        f.addAction(self.action_compare_book)
        f.addAction(self.action_quit)

        e = b.addMenu(_('&Edit'))
        e.addAction(self.action_global_undo)
        e.addAction(self.action_global_redo)
        e.addAction(self.action_create_checkpoint)
        e.addSeparator()
        e.addAction(self.action_editor_undo)
        e.addAction(self.action_editor_redo)
        e.addSeparator()
        e.addAction(self.action_editor_cut)
        e.addAction(self.action_editor_copy)
        e.addAction(self.action_editor_paste)
        e.addAction(self.action_insert_char)
        e.addSeparator()
        e.addAction(self.action_quick_edit)
        e.addAction(self.action_preferences)

        e = b.addMenu(_('&Tools'))
        tm = e.addMenu(_('Table of Contents'))
        tm.addAction(self.action_toc)
        tm.addAction(self.action_inline_toc)
        e.addAction(self.action_manage_fonts)
        e.addAction(self.action_embed_fonts)
        e.addAction(self.action_subset_fonts)
        e.addAction(self.action_compress_images)
        e.addAction(self.action_smarten_punctuation)
        e.addAction(self.action_remove_unused_css)
        e.addAction(self.action_transform_styles)
        e.addAction(self.action_fix_html_all)
        e.addAction(self.action_pretty_all)
        e.addAction(self.action_rationalize_folders)
        e.addAction(self.action_add_cover)
        e.addAction(self.action_set_semantics)
        e.addAction(self.action_filter_css)
        e.addAction(self.action_spell_check_book)
        er = e.addMenu(_('External &links'))
        er.addAction(self.action_check_external_links)
        er.addAction(self.action_get_ext_resources)
        e.addAction(self.action_check_book)
        e.addAction(self.action_reports)
        e.addAction(self.action_upgrade_book_internals)

        e = b.addMenu(_('&View'))
        t = e.addMenu(_('Tool&bars'))
        e.addSeparator()
        for name in sorted(actions, key=lambda x: sort_key(actions[x].text())):
            ac = actions[name]
            if name.endswith('-dock'):
                e.addAction(ac)
            elif name.endswith('-bar'):
                t.addAction(ac)
        e.addAction(self.action_browse_images)
        e.addSeparator()
        e.addAction(self.action_close_current_tab)
        e.addAction(self.action_close_all_but_current_tab)

        e = b.addMenu(_('&Search'))
        a = e.addAction
        a(self.action_find)
        e.addSeparator()
        a(self.action_find_next)
        a(self.action_find_previous)
        e.addSeparator()
        a(self.action_replace)
        a(self.action_replace_next)
        a(self.action_replace_previous)
        a(self.action_replace_all)
        e.addSeparator()
        a(self.action_count)
        e.addSeparator()
        a(self.action_mark)
        e.addSeparator()
        a(self.action_go_to_line)
        e.addSeparator()
        a(self.action_saved_searches)
        e.aboutToShow.connect(self.search_menu_about_to_show)
        e.addSeparator()
        a(self.action_text_search)

        if self.plugin_menu_actions:
            e = b.addMenu(_('&Plugins'))
            for ac in sorted(self.plugin_menu_actions,
                             key=lambda x: sort_key(unicode_type(x.text()))):
                e.addAction(ac)

        e = b.addMenu(_('&Help'))
        a = e.addAction
        a(self.action_help)
        a(QIcon(I('donate.png')), _('&Donate to support calibre development'),
          open_donate)
        a(self.action_preferences)
Esempio n. 42
0
 def names(self):
     for item in self._names.selectedItems():
         yield unicode_type(item.data(Qt.DisplayRole) or '')
Esempio n. 43
0
 def authors(self):
     ans = []
     for i in range(self.al.count()):
         ans.append(unicode_type(self.al.item(i).text()))
     return ans or [_('Unknown')]
Esempio n. 44
0
 def text(self):
     return unicode_type(self.lineEdit().text())
Esempio n. 45
0
 def show_initial_value(self, what):
     what = unicode_type(what) if what else u''
     self.setText(what)
     self.lineEdit().selectAll()
Esempio n. 46
0
 def update_link_clicked(self, url):
     url = unicode_type(url)
     if url.startswith('update:'):
         calibre_version, number_of_plugin_updates = msgpack_loads(from_hex_bytes(url[len('update:'):]))
         self.update_found(calibre_version, number_of_plugin_updates, force=True)
Esempio n. 47
0
 def item_chosen(self, index):
     if not self.isVisible():
         return
     self.hide()
     text = self.model().data(index, Qt.ItemDataRole.DisplayRole)
     self.item_selected.emit(unicode_type(text))
Esempio n. 48
0
    def run(self, path_to_output, opts, db, notification=DummyReporter()):
        from calibre.library import current_library_name
        from calibre.utils.date import isoformat
        from calibre.utils.html2text import html2text
        from calibre.utils.logging import default_log as log
        from lxml import etree
        from calibre.ebooks.metadata import authors_to_string

        self.fmt = path_to_output.rpartition('.')[2]
        self.notification = notification
        current_library = current_library_name()
        if getattr(opts, 'library_path', None):
            current_library = os.path.basename(opts.library_path)

        if opts.verbose:
            opts_dict = vars(opts)
            log("%s('%s'): Generating %s" %
                (self.name, current_library, self.fmt.upper()))
            if opts.connected_device['is_device_connected']:
                log(" connected_device: %s" % opts.connected_device['name'])
            if opts_dict['search_text']:
                log(" --search='%s'" % opts_dict['search_text'])

            if opts_dict['ids']:
                log(" Book count: %d" % len(opts_dict['ids']))
                if opts_dict['search_text']:
                    log(" (--search ignored when a subset of the database is specified)"
                        )

            if opts_dict['fields']:
                if opts_dict['fields'] == 'all':
                    log(" Fields: %s" % ', '.join(FIELDS[1:]))
                else:
                    log(" Fields: %s" % opts_dict['fields'])

        # If a list of ids are provided, don't use search_text
        if opts.ids:
            opts.search_text = None

        data = self.search_sort_db(db, opts)

        if not len(data):
            log.error(
                "\nNo matching database entries for search criteria '%s'" %
                opts.search_text)
            # raise SystemExit(1)

        # Get the requested output fields as a list
        fields = self.get_output_fields(db, opts)

        # If connected device, add 'On Device' values to data
        if opts.connected_device[
                'is_device_connected'] and 'ondevice' in fields:
            for entry in data:
                entry['ondevice'] = db.catalog_plugin_on_device_temp_mapping[
                    entry['id']]['ondevice']

        fm = {x: db.field_metadata.get(x, {}) for x in fields}

        if self.fmt == 'csv':
            outfile = codecs.open(path_to_output, 'w', 'utf8')

            # Write a UTF-8 BOM
            outfile.write('\ufeff')

            # Output the field headers
            outfile.write('%s\n' % ','.join(fields))

            # Output the entry fields
            for entry in data:
                outstr = []
                for field in fields:
                    if field.startswith('#'):
                        item = db.get_field(entry['id'],
                                            field,
                                            index_is_id=True)
                        if isinstance(item, (list, tuple)):
                            if fm.get(field,
                                      {}).get('display',
                                              {}).get('is_names', False):
                                item = ' & '.join(item)
                            else:
                                item = ', '.join(item)
                    elif field == 'library_name':
                        item = current_library
                    elif field == 'title_sort':
                        item = entry['sort']
                    else:
                        item = entry[field]

                    if item is None:
                        outstr.append('""')
                        continue
                    elif field == 'formats':
                        fmt_list = []
                        for format in item:
                            fmt_list.append(format.rpartition('.')[2].lower())
                        item = ', '.join(fmt_list)
                    elif field == 'authors':
                        item = authors_to_string(item)
                    elif field == 'tags':
                        item = ', '.join(item)
                    elif field == 'isbn':
                        # Could be 9, 10 or 13 digits, with hyphens, possibly ending in 'X'
                        item = '%s' % re.sub(r'[^\dX-]', '', item)
                    elif fm.get(field, {}).get('datatype') == 'datetime':
                        item = isoformat(item, as_utc=False)
                    elif field == 'comments':
                        item = item.replace('\r\n', ' ')
                        item = item.replace('\n', ' ')
                    elif fm.get(field, {}).get('datatype',
                                               None) == 'rating' and item:
                        item = '%.2g' % (item / 2)

                    # Convert HTML to markdown text
                    if isinstance(item, unicode_type):
                        opening_tag = re.search(r'<(\w+)( |>)', item)
                        if opening_tag:
                            closing_tag = re.search(
                                r'<\/%s>$' % opening_tag.group(1), item)
                            if closing_tag:
                                item = html2text(item)

                    outstr.append('"%s"' %
                                  unicode_type(item).replace('"', '""'))

                outfile.write(','.join(outstr) + '\n')
            outfile.close()

        elif self.fmt == 'xml':
            from lxml.builder import E

            if getattr(opts, 'catalog_title', None):
                root = E.calibredb(title=opts.catalog_title)
            else:
                root = E.calibredb()
            for r in data:
                record = E.record()
                root.append(record)

                for field in fields:
                    if field.startswith('#'):
                        val = db.get_field(r['id'], field, index_is_id=True)
                        if not isinstance(val, unicode_type):
                            val = unicode_type(val)
                        item = getattr(E, field.replace('#', '_'))(val)
                        record.append(item)

                for field in ('id', 'uuid', 'publisher', 'rating', 'size',
                              'isbn', 'ondevice', 'identifiers'):
                    if field in fields:
                        val = r[field]
                        if not val:
                            continue
                        if not isinstance(val, (bytes, unicode_type)):
                            if (fm.get(field, {}).get('datatype', None)
                                    == 'rating' and val):
                                val = '%.2g' % (val / 2)
                            val = unicode_type(val)
                        item = getattr(E, field)(val)
                        record.append(item)

                if 'title' in fields:
                    title = E.title(r['title'], sort=r['sort'])
                    record.append(title)

                if 'authors' in fields:
                    aus = E.authors(sort=r['author_sort'])
                    for au in r['authors']:
                        aus.append(E.author(au))
                    record.append(aus)

                for field in ('timestamp', 'pubdate'):
                    if field in fields:
                        record.append(
                            getattr(E, field)(isoformat(r[field],
                                                        as_utc=False)))

                if 'tags' in fields and r['tags']:
                    tags = E.tags()
                    for tag in r['tags']:
                        tags.append(E.tag(tag))
                    record.append(tags)

                if 'comments' in fields and r['comments']:
                    record.append(E.comments(r['comments']))

                if 'series' in fields and r['series']:
                    record.append(
                        E.series(r['series'],
                                 index=unicode_type(r['series_index'])))

                if 'languages' in fields and r['languages']:
                    record.append(E.languages(r['languages']))

                if 'cover' in fields and r['cover']:
                    record.append(E.cover(r['cover'].replace(os.sep, '/')))

                if 'formats' in fields and r['formats']:
                    fmt = E.formats()
                    for f in r['formats']:
                        fmt.append(E.format(f.replace(os.sep, '/')))
                    record.append(fmt)

                if 'library_name' in fields:
                    record.append(E.library_name(current_library))

            with open(path_to_output, 'wb') as f:
                f.write(
                    etree.tostring(root,
                                   encoding='utf-8',
                                   xml_declaration=True,
                                   pretty_print=True))
Esempio n. 49
0
 def template(self):
     return unicode_type(self.t.text()).strip()
Esempio n. 50
0
 def javaScriptAlert(self, origin, msg):
     self.log(unicode_type(msg))
Esempio n. 51
0
 def javaScriptConsoleMessage(self, level, msg, lineno, msgid):
     self.log('JS:', unicode_type(msg))
Esempio n. 52
0
 def find(self, forwards=True):
     text = unicode_type(self.search_text.text()).strip()
     flags = QWebEnginePage.FindFlags(0) if forwards else QWebEnginePage.FindBackward
     self.find_data = text, flags, forwards
     self.view.findText(text, flags, self.find_callback)
Esempio n. 53
0
 def setModelData(self, editor, model, index):
     authors = string_to_authors(unicode_type(editor.text()))
     model.setData(index, authors[0])
     self.edited.emit(index.row())
Esempio n. 54
0
def book_to_json(ctx,
                 rd,
                 db,
                 book_id,
                 get_category_urls=True,
                 device_compatible=False,
                 device_for_template=None):
    mi = db.get_metadata(book_id, get_cover=False)
    codec = JsonCodec(db.field_metadata)
    if not device_compatible:
        try:
            mi.rating = mi.rating / 2.
        except Exception:
            mi.rating = 0.0
    data = codec.encode_book_metadata(mi)
    for x in ('publication_type', 'size', 'db_id', 'lpath', 'mime', 'rights',
              'book_producer'):
        data.pop(x, None)

    get = partial(ctx.url_for,
                  get_content,
                  book_id=book_id,
                  library_id=db.server_library_id)
    data['cover'] = get(what='cover')
    data['thumbnail'] = get(what='thumb')

    if not device_compatible:
        mi.format_metadata = {
            k.lower(): dict(v)
            for k, v in iteritems(mi.format_metadata)
        }
        for v in itervalues(mi.format_metadata):
            mtime = v.get('mtime', None)
            if mtime is not None:
                v['mtime'] = isoformat(mtime, as_utc=True)
        data['format_metadata'] = mi.format_metadata
        fmts = set(x.lower() for x in mi.format_metadata)
        pf = prefs['output_format'].lower()
        other_fmts = list(fmts)
        try:
            fmt = pf if pf in fmts else other_fmts[0]
        except:
            fmt = None
        if fmts and fmt:
            other_fmts = [x for x in fmts if x != fmt]
        data['formats'] = sorted(fmts)
        if fmt:
            data['main_format'] = {fmt: get(what=fmt)}
        else:
            data['main_format'] = None
        data['other_formats'] = {fmt: get(what=fmt) for fmt in other_fmts}

        if get_category_urls:
            category_urls = data['category_urls'] = {}
            all_cats = ctx.get_categories(rd, db)
            for key in mi.all_field_keys():
                fm = mi.metadata_for_field(key)
                if (fm and fm['is_category'] and not fm['is_csp']
                        and key != 'formats' and fm['datatype'] != 'rating'):
                    categories = mi.get(key) or []
                    if isinstance(categories, string_or_bytes):
                        categories = [categories]
                    category_urls[key] = dbtags = {}
                    for category in categories:
                        for tag in all_cats.get(key, ()):
                            if tag.original_name == category:
                                dbtags[category] = ctx.url_for(
                                    books_in,
                                    encoded_category=encode_name(
                                        tag.category if tag.category else key),
                                    encoded_item=encode_name(
                                        tag.original_name if tag.id is None
                                        else unicode_type(tag.id)),
                                    library_id=db.server_library_id)
                                break
    else:
        series = data.get('series', None) or ''
        if series:
            tsorder = tweaks['save_template_title_series_sorting']
            series = title_sort(series, order=tsorder)
        data['_series_sort_'] = series
        if device_for_template:
            import posixpath
            from calibre.devices.utils import create_upload_path
            from calibre.utils.filenames import ascii_filename as sanitize
            from calibre.customize.ui import device_plugins

            for device_class in device_plugins():
                if device_class.__class__.__name__ == device_for_template:
                    template = device_class.save_template()
                    data['_filename_'] = create_upload_path(
                        mi, book_id, template, sanitize, path_type=posixpath)
                    break

    return data, mi.last_modified
Esempio n. 55
0
def identify(
        log,
        abort,  # {{{
        title=None,
        authors=None,
        identifiers={},
        timeout=30,
        allowed_plugins=None):
    if title == _('Unknown'):
        title = None
    if authors == [_('Unknown')]:
        authors = None
    start_time = time.time()

    plugins = [
        p for p in metadata_plugins(['identify']) if p.is_configured() and (
            allowed_plugins is None or p.name in allowed_plugins)
    ]

    kwargs = {
        'title': title,
        'authors': authors,
        'identifiers': identifiers,
        'timeout': timeout,
    }

    log('Running identify query with parameters:')
    log(kwargs)
    log('Using plugins:',
        ', '.join(['%s %s' % (p.name, p.version) for p in plugins]))
    log('The log from individual plugins is below')

    workers = [Worker(p, kwargs, abort) for p in plugins]
    for w in workers:
        w.start()

    first_result_at = None
    results = {}
    for p in plugins:
        results[p] = []
    logs = dict([(w.plugin, w.buf) for w in workers])

    def get_results():
        found = False
        for w in workers:
            try:
                result = w.rq.get_nowait()
            except Empty:
                pass
            else:
                results[w.plugin].append(result)
                found = True
        return found

    wait_time = msprefs['wait_after_first_identify_result']
    while True:
        time.sleep(0.2)

        if get_results() and first_result_at is None:
            first_result_at = time.time()

        if not is_worker_alive(workers):
            break

        if (first_result_at is not None
                and time.time() - first_result_at > wait_time):
            log.warn('Not waiting any longer for more results. Still running'
                     ' sources:')
            for worker in workers:
                if worker.is_alive():
                    log.debug('\t' + worker.name)
            abort.set()
            break

    while not abort.is_set() and get_results():
        pass

    sort_kwargs = dict(kwargs)
    for k in list(sort_kwargs):
        if k not in ('title', 'authors', 'identifiers'):
            sort_kwargs.pop(k)

    longest, lp = -1, ''
    for plugin, presults in iteritems(results):
        presults.sort(key=plugin.identify_results_keygen(**sort_kwargs))

        # Throw away lower priority results from the same source that have exactly the same
        # title and authors as a higher priority result
        filter_results = set()
        filtered_results = []
        for r in presults:
            key = (r.title, tuple(r.authors))
            if key not in filter_results:
                filtered_results.append(r)
                filter_results.add(key)
        results[plugin] = presults = filtered_results

        plog = logs[plugin].getvalue().strip()
        log('\n' + '*' * 30, plugin.name, '%s' % (plugin.version, ), '*' * 30)
        log('Found %d results' % len(presults))
        time_spent = getattr(plugin, 'dl_time_spent', None)
        if time_spent is None:
            log('Downloading was aborted')
            longest, lp = -1, plugin.name
        else:
            log('Downloading from', plugin.name, 'took', time_spent)
            if time_spent > longest:
                longest, lp = time_spent, plugin.name
        for r in presults:
            log('\n\n---')
            try:
                log(unicode_type(r))
            except TypeError:
                log(repr(r))
        if plog:
            log(plog)
        log('\n' + '*' * 80)

        dummy = Metadata(_('Unknown'))
        for i, result in enumerate(presults):
            for f in plugin.prefs['ignore_fields']:
                if ':' not in f:
                    setattr(result, f, getattr(dummy, f))
                if f == 'series':
                    result.series_index = dummy.series_index
            result.relevance_in_source = i
            result.has_cached_cover_url = (plugin.cached_cover_url_is_reliable
                                           and plugin.get_cached_cover_url(
                                               result.identifiers) is not None)
            result.identify_plugin = plugin
            if msprefs['txt_comments']:
                if plugin.has_html_comments and result.comments:
                    result.comments = html2text(result.comments)

    log('The identify phase took %.2f seconds' % (time.time() - start_time))
    log('The longest time (%f) was taken by:' % longest, lp)
    log('Merging results from different sources')
    start_time = time.time()
    results = merge_identify_results(results, log)

    log('We have %d merged results, merging took: %.2f seconds' %
        (len(results), time.time() - start_time))
    tm_rules = msprefs['tag_map_rules']
    if tm_rules:
        from calibre.ebooks.metadata.tag_mapper import map_tags
    am_rules = msprefs['author_map_rules']
    if am_rules:
        from calibre.ebooks.metadata.author_mapper import map_authors, compile_rules
        am_rules = compile_rules(am_rules)

    max_tags = msprefs['max_tags']
    for r in results:
        if tm_rules:
            r.tags = map_tags(r.tags, tm_rules)
        r.tags = r.tags[:max_tags]
        if getattr(r.pubdate, 'year', 2000) <= UNDEFINED_DATE.year:
            r.pubdate = None

    if msprefs['swap_author_names']:
        for r in results:

            def swap_to_ln_fn(a):
                if ',' in a:
                    return a
                parts = a.split(None)
                if len(parts) <= 1:
                    return a
                surname = parts[-1]
                return '%s, %s' % (surname, ' '.join(parts[:-1]))

            r.authors = [swap_to_ln_fn(a) for a in r.authors]

    if am_rules:
        for r in results:
            new_authors = map_authors(r.authors, am_rules)
            if new_authors != r.authors:
                r.authors = new_authors
                r.author_sort = authors_to_sort_string(r.authors)

    return results
Esempio n. 56
0
 def icon_to_clipboard(self):
     app = QApplication.instance()
     c = app.clipboard()
     c.setText(unicode_type(self.icon_files.currentText()))
Esempio n. 57
0
    def do_book(self):
        if self.i >= len(self.book_ids):
            return self.do_queue()
        book_id = self.book_ids[self.i]
        self.i += 1

        temp_files = []

        try:
            input_format = get_input_format_for_book(self.db, book_id, None)[0]
            input_fmt = self.db.original_fmt(book_id, input_format).lower()
            same_fmt = input_fmt == self.output_format.lower()
            mi, opf_file = create_opf_file(self.db, book_id)
            in_file = PersistentTemporaryFile('.' + input_format)
            with in_file:
                self.db.copy_format_to(book_id,
                                       input_fmt,
                                       in_file,
                                       index_is_id=True)

            out_file = PersistentTemporaryFile('.' + self.output_format)
            out_file.write(as_bytes(self.output_format))
            out_file.close()
            temp_files = [in_file]

            combined_recs = GuiRecommendations()
            default_recs = bulk_defaults_for_input_format(input_format)
            for key in default_recs:
                combined_recs[key] = default_recs[key]
            if self.use_saved_single_settings:
                specific_recs = load_specifics(self.db, book_id)
                for key in specific_recs:
                    combined_recs[key] = specific_recs[key]
            for item in self.user_recs:
                combined_recs[item[0]] = item[1]
            save_specifics(self.db, book_id, combined_recs)
            lrecs = list(combined_recs.to_recommendations())
            from calibre.customize.ui import plugin_for_output_format
            op = plugin_for_output_format(self.output_format)
            if op and op.recommendations:
                prec = {x[0] for x in op.recommendations}
                for i, r in enumerate(list(lrecs)):
                    if r[0] in prec:
                        lrecs[i] = (r[0], r[1], OptionRecommendation.HIGH)

            cover_file = create_cover_file(self.db, book_id)

            if opf_file is not None:
                lrecs.append(('read_metadata_from_opf', opf_file.name,
                              OptionRecommendation.HIGH))
                temp_files.append(opf_file)
            if cover_file is not None:
                lrecs.append(
                    ('cover', cover_file.name, OptionRecommendation.HIGH))
                temp_files.append(cover_file)

            for x in list(lrecs):
                if x[0] == 'debug_pipeline':
                    lrecs.remove(x)
            try:
                dtitle = unicode_type(mi.title)
            except:
                dtitle = repr(mi.title)
            if len(dtitle) > 50:
                dtitle = dtitle[:50].rpartition(' ')[0] + '...'
            self.setLabelText(_('Queueing ') + dtitle)
            desc = _('Convert book %(num)d of %(tot)d (%(title)s)') % dict(
                num=self.i, tot=len(self.book_ids), title=dtitle)

            args = [in_file.name, out_file.name, lrecs]
            temp_files.append(out_file)
            func = 'gui_convert_override'
            if same_fmt:
                func += ':same_fmt'
            self.jobs.append((func, args, desc, self.output_format.upper(),
                              book_id, temp_files))

            self.changed = True
            self.setValue(self.i)
        except NoSupportedInputFormats:
            self.bad.append(book_id)
        QTimer.singleShot(0, self.do_book)
Esempio n. 58
0
def convert_single_ebook(
        parent,
        db,
        book_ids,
        auto_conversion=False,  # {{{
        out_format=None,
        show_no_format_warning=True):
    changed = False
    jobs = []
    bad = []

    total = len(book_ids)
    if total == 0:
        return None, None, None

    for i, book_id in enumerate(book_ids):
        temp_files = []

        try:
            d = SingleConfig(parent, db, book_id, None, out_format)

            if auto_conversion:
                d.accept()
                result = QDialog.Accepted
            else:
                result = d.exec_()

            if result == QDialog.Accepted:
                # if not convert_existing(parent, db, [book_id], d.output_format):
                #    continue

                mi = db.get_metadata(book_id, True)
                in_file = PersistentTemporaryFile('.' + d.input_format)
                with in_file:
                    input_fmt = db.original_fmt(book_id,
                                                d.input_format).lower()
                    same_fmt = input_fmt == d.output_format.lower()
                    db.copy_format_to(book_id,
                                      input_fmt,
                                      in_file,
                                      index_is_id=True)

                out_file = PersistentTemporaryFile('.' + d.output_format)
                out_file.write(as_bytes(d.output_format))
                out_file.close()
                temp_files = [in_file]

                try:
                    dtitle = unicode_type(mi.title)
                except:
                    dtitle = repr(mi.title)
                desc = _('Convert book %(num)d of %(total)d (%(title)s)') % \
                        {'num':i + 1, 'total':total, 'title':dtitle}

                recs = d.recommendations
                if d.opf_file is not None:
                    recs.append(('read_metadata_from_opf', d.opf_file.name,
                                 OptionRecommendation.HIGH))
                    temp_files.append(d.opf_file)
                if d.cover_file is not None:
                    recs.append(('cover', d.cover_file.name,
                                 OptionRecommendation.HIGH))
                    temp_files.append(d.cover_file)
                args = [in_file.name, out_file.name, recs]
                temp_files.append(out_file)
                func = 'gui_convert_override'
                parts = []
                if not auto_conversion and d.manually_fine_tune_toc:
                    parts.append('manually_fine_tune_toc')
                if same_fmt:
                    parts.append('same_fmt')
                if parts:
                    func += ':%s' % (';'.join(parts))
                jobs.append((func, args, desc, d.output_format.upper(),
                             book_id, temp_files))

                changed = True
                d.break_cycles()
        except NoSupportedInputFormats as nsif:
            bad.append((book_id, nsif.available_formats))

    if bad and show_no_format_warning:
        if len(bad) == 1 and not bad[0][1]:
            title = db.title(bad[0][0], True)
            warning_dialog(
                parent,
                _('Could not convert'),
                '<p>' +
                _('Could not convert <b>%s</b> as it has no e-book files. If you '
                  'think it should have files, but calibre is not finding '
                  'them, that is most likely because you moved the book\'s '
                  'files around outside of calibre. You will need to find those files '
                  'and re-add them to calibre.') % title,
                show=True)
        else:
            res = []
            for id, available_formats in bad:
                title = db.title(id, True)
                if available_formats:
                    msg = _('No supported formats (Available formats: %s)') % (
                        ', '.join(available_formats))
                else:
                    msg = _('This book has no actual e-book files')
                res.append('%s - %s' % (title, msg))

            msg = '%s' % '\n'.join(res)
            warning_dialog(parent, _('Could not convert some books'), (_(
                'Could not convert the book because no supported source format was found'
            ) if len(res) == 1 else _(
                'Could not convert {num} of {tot} books, because no supported source formats were found.'
            )).format(num=len(res), tot=total), msg).exec_()

    return jobs, changed, bad
Esempio n. 59
0
def safe_ord(x):
    return ord_string(unicode_type(x))[0]
Esempio n. 60
0
    def accept(self):
        n = unicode_type(self.vl_name.currentText()).strip()
        if not n:
            error_dialog(
                self.gui,
                _('No name'),
                _('You must provide a name for the new Virtual library'),
                show=True)
            return

        if n.startswith('*'):
            error_dialog(self.gui,
                         _('Invalid name'),
                         _('A Virtual library name cannot begin with "*"'),
                         show=True)
            return

        if n in self.existing_names and n != self.editing:
            if not question_dialog(
                    self.gui,
                    _('Name already in use'),
                    _('That name is already in use. Do you want to replace it '
                      'with the new search?'),
                    default_yes=False):
                return

        v = unicode_type(self.vl_text.text()).strip()
        if not v:
            error_dialog(
                self.gui,
                _('No search string'),
                _('You must provide a search to define the new Virtual library'
                  ),
                show=True)
            return

        try:
            db = self.gui.library_view.model().db
            recs = db.data.search_getting_ids('',
                                              v,
                                              use_virtual_library=False,
                                              sort_results=False)
        except ParseException as e:
            error_dialog(self.gui,
                         _('Invalid search'),
                         _('The search in the search box is not valid'),
                         det_msg=e.msg,
                         show=True)
            return

        if not recs and not question_dialog(
                self.gui,
                _('Search found no books'),
                _('The search found no books, so the Virtual library '
                  'will be empty. Do you really want to use that search?'),
                default_yes=False):
            return

        self.library_name = n
        self.library_search = v
        QDialog.accept(self)