Example #1
0
def cdb_add_book(ctx, rd, job_id, add_duplicates, filename, library_id):
    '''
    Add a file as a new book. The file contents must be in the body of the request.

    The response will also have the title/authors/languages read from the
    metadata of the file/filename. It will contain a `book_id` field specifying the id of the newly added book,
    or if add_duplicates is not specified and a duplicate was found, no book_id will be present. It will also
    return the value of `job_id` as the `id` field and `filename` as the `filename` field.
    '''
    db = get_db(ctx, rd, library_id)
    if ctx.restriction_for(rd, db):
        raise HTTPForbidden('Cannot use the add book interface with a user who has per library restrictions')
    if not filename:
        raise HTTPBadRequest('An empty filename is not allowed')
    sfilename = sanitize_file_name_unicode(filename)
    fmt = os.path.splitext(sfilename)[1]
    fmt = fmt[1:] if fmt else None
    if not fmt:
        raise HTTPBadRequest('An filename with no extension is not allowed')
    if isinstance(rd.request_body_file, BytesIO):
        raise HTTPBadRequest('A request body containing the file data must be specified')
    add_duplicates = add_duplicates in ('y', '1')
    path = os.path.join(rd.tdir, sfilename)
    rd.request_body_file.name = path
    rd.request_body_file.seek(0)
    mi = get_metadata(rd.request_body_file, stream_type=fmt, use_libprs_metadata=True)
    rd.request_body_file.seek(0)
    ids, duplicates = db.add_books([(mi, {fmt: rd.request_body_file})], add_duplicates=add_duplicates)
    ans = {'title': mi.title, 'authors': mi.authors, 'languages': mi.languages, 'filename': filename, 'id': job_id}
    if ids:
        ans['book_id'] = ids[0]
        books_added(ids)
    return ans
Example #2
0
 def filename_button_clicked(self):
     try:
         path = choose_files(self, 'choose_category_icon',
                     _('Select Icon'), filters=[
                     ('Images', ['png', 'gif', 'jpg', 'jpeg'])],
                 all_files=False, select_only_single_file=True)
         if path:
             icon_path = path[0]
             icon_name = sanitize_file_name_unicode(
                          os.path.splitext(
                                os.path.basename(icon_path))[0]+'.png')
             if icon_name not in self.icon_file_names:
                 self.icon_file_names.append(icon_name)
                 self.update_filename_box()
                 try:
                     p = QIcon(icon_path).pixmap(QSize(128, 128))
                     d = os.path.join(config_dir, 'cc_icons')
                     if not os.path.exists(os.path.join(d, icon_name)):
                         if not os.path.exists(d):
                             os.makedirs(d)
                         with open(os.path.join(d, icon_name), 'wb') as f:
                             f.write(pixmap_to_data(p, format='PNG'))
                 except:
                     traceback.print_exc()
             self.icon_files.setCurrentIndex(self.icon_files.findText(icon_name))
             self.icon_files.adjustSize()
     except:
         traceback.print_exc()
     return
Example #3
0
    def catalog_generated(self, job):
        if job.result:
            # Problems during catalog generation
            # jobs.results is a list - the first entry is the intended title for the dialog
            # Subsequent strings are error messages
            dialog_title = job.result.pop(0)
            if re.match('warning:', job.result[0].lower()):
                msg = _("Catalog generation complete, with warnings.")
                warning_dialog(self.gui, dialog_title, msg, det_msg='\n'.join(job.result), show=True)
            else:
                job.result.append("Catalog generation terminated.")
                error_dialog(self.gui, dialog_title,'\n'.join(job.result),show=True)
                return

        if job.failed:
            return self.gui.job_exception(job)
        id = self.gui.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title)
        self.gui.library_view.model().reset()
        if job.catalog_sync:
            sync = dynamic.get('catalogs_to_be_synced', set([]))
            sync.add(id)
            dynamic.set('catalogs_to_be_synced', sync)
        self.gui.status_bar.show_message(_('Catalog generated.'), 3000)
        self.gui.sync_catalogs()
        if job.fmt not in ['EPUB','MOBI']:
            export_dir = choose_dir(self.gui, _('Export Catalog Directory'),
                    _('Select destination for %(title)s.%(fmt)s') % dict(
                        title=job.catalog_title, fmt=job.fmt.lower()))
            if export_dir:
                destination = os.path.join(export_dir, '%s.%s' % (
                    sanitize_file_name_unicode(job.catalog_title), job.fmt.lower()))
                shutil.copyfile(job.catalog_file_path, destination)
Example #4
0
 def rename_requested(self, name, location):
     loc = location.replace('/', os.sep)
     base = os.path.dirname(loc)
     newname, ok = QInputDialog.getText(self.gui, _('Rename') + ' ' + name,
             '<p>'+_('Choose a new name for the library <b>%s</b>. ')%name +
             '<p>'+_('Note that the actual library folder will be renamed.'),
             text=name)
     newname = sanitize_file_name_unicode(unicode(newname))
     if not ok or not newname or newname == name:
         return
     newloc = os.path.join(base, newname)
     if os.path.exists(newloc):
         return error_dialog(self.gui, _('Already exists'),
                 _('The folder %s already exists. Delete it first.') %
                 newloc, show=True)
     if (iswindows and len(newloc) >
             LibraryDatabase2.WINDOWS_LIBRARY_PATH_LIMIT):
         return error_dialog(self.gui, _('Too long'),
                 _('Path to library too long. Must be less than'
                 ' %d characters.')%LibraryDatabase2.WINDOWS_LIBRARY_PATH_LIMIT,
                 show=True)
     try:
         os.rename(loc, newloc)
     except:
         import traceback
         error_dialog(self.gui, _('Rename failed'),
                 _('Failed to rename the library at %s. '
             'The most common cause for this is if one of the files'
             ' in the library is open in another program.') % loc,
                 det_msg=traceback.format_exc(), show=True)
         return
     self.stats.rename(location, newloc)
     self.build_menus()
     self.gui.iactions['Copy To Library'].build_menus()
Example #5
0
 def request_bulk_rename(self):
     names = {unicode(item.data(0, NAME_ROLE).toString()) for item in self.selectedItems()}
     bad = names & current_container().names_that_must_not_be_changed
     if bad:
         return error_dialog(self, _('Cannot rename'),
                      _('The file(s) %s cannot be renamed.') % ('<b>%s</b>' % ', '.join(bad)), show=True)
     names = sorted(names, key=self.index_of_name)
     d = QDialog(self)
     d.l = l = QFormLayout(d)
     d.setLayout(l)
     d.prefix = p = QLineEdit(d)
     p.setText(_('Chapter-'))
     p.selectAll()
     d.la = la = QLabel(_(
         'All selected files will be renamed to the form prefix-number'))
     l.addRow(la)
     l.addRow(_('&Prefix:'), p)
     d.num = num = QSpinBox(d)
     num.setMinimum(0), num.setValue(1), num.setMaximum(1000)
     l.addRow(_('Starting &number:'), num)
     d.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
     bb.accepted.connect(d.accept), bb.rejected.connect(d.reject)
     l.addRow(bb)
     if d.exec_() == d.Accepted:
         prefix = sanitize_file_name_unicode(unicode(d.prefix.text()))
         num = d.num.value()
         largest = num + len(names) - 1
         fmt = '%0{0}d'.format(len(str(largest)))
         def change_name(name, num):
             parts = name.split('/')
             base, ext = parts[-1].rpartition('.')[0::2]
             parts[-1] = prefix + (fmt % num) + '.' + ext
             return '/'.join(parts)
         name_map = {n:change_name(n, num + i) for i, n in enumerate(names)}
         self.bulk_rename_requested.emit(name_map)
Example #6
0
def book_filename(rd, book_id, mi, fmt, as_encoded_unicode=False):
    au = authors_to_string(mi.authors or [_('Unknown')])
    title = mi.title or _('Unknown')
    ext = (fmt or '').lower()
    if ext == 'kepub' and 'Kobo Touch' in rd.inheaders.get('User-Agent', ''):
        ext = 'kepub.epub'
    fname = '%s - %s_%s.%s' % (title[:30], au[:30], book_id, ext)
    if as_encoded_unicode:
        # See https://tools.ietf.org/html/rfc6266
        fname = sanitize_file_name_unicode(fname).encode('utf-8')
        fname = quote(fname).decode('ascii')
    else:
        fname = ascii_filename(fname).replace('"', '_')
    return fname
Example #7
0
def name_is_ok(name, show_error):
    if not name or not name.strip():
        return show_error('') and False
    ext = name.rpartition('.')[-1]
    if not ext or ext == name:
        return show_error(_('The file name must have an extension')) and False
    norm = name.replace('\\', '/')
    parts = name.split('/')
    for x in parts:
        if sanitize_file_name_unicode(x) != x:
            return show_error(_('The file name contains invalid characters')) and False
    if current_container().has_name(norm):
        return show_error(_('This file name already exists in the book')) and False
    show_error('')
    return True
Example #8
0
 def name_is_ok(self):
     name = unicode(self.name.text())
     if not name or not name.strip():
         return self.show_error("")
     ext = name.rpartition(".")[-1]
     if not ext or ext == name:
         return self.show_error(_("The file name must have an extension"))
     norm = name.replace("\\", "/")
     parts = name.split("/")
     for x in parts:
         if sanitize_file_name_unicode(x) != x:
             return self.show_error(_("The file name contains invalid characters"))
     if current_container().has_name(norm):
         return self.show_error(_("This file name already exists in the book"))
     self.show_error("")
     return True
Example #9
0
 def rename_requested(self, name, location):
     LibraryDatabase = db_class()
     loc = location.replace('/', os.sep)
     base = os.path.dirname(loc)
     old_name = name.replace('&&', '&')
     newname, ok = QInputDialog.getText(self.gui, _('Rename') + ' ' + old_name,
             '<p>'+_('Choose a new name for the library <b>%s</b>. ')%name +
             '<p>'+_('Note that the actual library folder will be renamed.'),
             text=old_name)
     newname = sanitize_file_name_unicode(unicode(newname))
     if not ok or not newname or newname == old_name:
         return
     newloc = os.path.join(base, newname)
     if os.path.exists(newloc):
         return error_dialog(self.gui, _('Already exists'),
                 _('The folder %s already exists. Delete it first.') %
                 newloc, show=True)
     if (iswindows and len(newloc) >
             LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT):
         return error_dialog(self.gui, _('Too long'),
                 _('Path to library too long. Must be less than'
                 ' %d characters.')%LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT,
                 show=True)
     if not os.path.exists(loc):
         error_dialog(self.gui, _('Not found'),
                 _('Cannot rename as no library was found at %s. '
                   'Try switching to this library first, then switch back '
                   'and retry the renaming.')%loc, show=True)
         return
     self.gui.library_broker.remove_library(loc)
     try:
         os.rename(loc, newloc)
     except:
         import traceback
         det_msg = 'Location: %r New Location: %r\n%s'%(loc, newloc,
                                                     traceback.format_exc())
         error_dialog(self.gui, _('Rename failed'),
                 _('Failed to rename the library at %s. '
             'The most common cause for this is if one of the files'
             ' in the library is open in another program.') % loc,
                 det_msg=det_msg, show=True)
         return
     self.stats.rename(location, newloc)
     self.build_menus()
     self.gui.iactions['Copy To Library'].build_menus()
Example #10
0
 def name_is_ok(self):
     name = unicode(self.name.text())
     if not name or not name.strip():
         return self.show_error('')
     ext = name.rpartition('.')[-1]
     if not ext or ext == name:
         return self.show_error(_('The file name must have an extension'))
     norm = name.replace('\\', '/')
     parts = name.split('/')
     for x in parts:
         if sanitize_file_name_unicode(x) != x:
             return self.show_error(
                 _('The file name contains invalid characters'))
     if current_container().has_name(norm):
         return self.show_error(
             _('This file name already exists in the book'))
     self.show_error('')
     return True
Example #11
0
 def rename_requested(self, name, location):
     LibraryDatabase = db_class()
     loc = location.replace('/', os.sep)
     base = os.path.dirname(loc)
     old_name = name.replace('&&', '&')
     newname, ok = QInputDialog.getText(self.gui, _('Rename') + ' ' + old_name,
             '<p>'+_('Choose a new name for the library <b>%s</b>. ')%name +
             '<p>'+_('Note that the actual library folder will be renamed.'),
             text=old_name)
     newname = sanitize_file_name_unicode(unicode(newname))
     if not ok or not newname or newname == old_name:
         return
     newloc = os.path.join(base, newname)
     if os.path.exists(newloc):
         return error_dialog(self.gui, _('Already exists'),
                 _('The folder %s already exists. Delete it first.') %
                 newloc, show=True)
     if (iswindows and len(newloc) >
             LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT):
         return error_dialog(self.gui, _('Too long'),
                 _('Path to library too long. Must be less than'
                 ' %d characters.')%LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT,
                 show=True)
     if not os.path.exists(loc):
         error_dialog(self.gui, _('Not found'),
                 _('Cannot rename as no library was found at %s. '
                   'Try switching to this library first, then switch back '
                   'and retry the renaming.')%loc, show=True)
         return
     try:
         os.rename(loc, newloc)
     except:
         import traceback
         det_msg = 'Location: %r New Location: %r\n%s'%(loc, newloc,
                                                     traceback.format_exc())
         error_dialog(self.gui, _('Rename failed'),
                 _('Failed to rename the library at %s. '
             'The most common cause for this is if one of the files'
             ' in the library is open in another program.') % loc,
                 det_msg=det_msg, show=True)
         return
     self.stats.rename(location, newloc)
     self.build_menus()
     self.gui.iactions['Copy To Library'].build_menus()
Example #12
0
    def catalog_generated(self, job):
        if job.result:
            # Problems during catalog generation
            # jobs.results is a list - the first entry is the intended title for the dialog
            # Subsequent strings are error messages
            dialog_title = job.result.pop(0)
            if re.search('warning', job.result[0].lower()):
                msg = _("Catalog generation complete, with warnings.")
                warning_dialog(self.gui, dialog_title, msg, det_msg='\n'.join(job.result), show=True)
            else:
                job.result.append("Catalog generation terminated.")
                error_dialog(self.gui, dialog_title,'\n'.join(job.result),show=True)
                return

        if job.failed:
            return self.gui.job_exception(job)
        if dynamic.get('catalog_add_to_library', True):
            id = self.gui.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title)
            self.gui.library_view.model().beginResetModel(), self.gui.library_view.model().endResetModel()
            if job.catalog_sync:
                sync = dynamic.get('catalogs_to_be_synced', set([]))
                sync.add(id)
                dynamic.set('catalogs_to_be_synced', sync)
        self.gui.status_bar.show_message(_('Catalog generated.'), 3000)
        self.gui.sync_catalogs()
        if not dynamic.get('catalog_add_to_library', True) or job.fmt not in {'EPUB','MOBI', 'AZW3'}:
            export_dir = choose_dir(self.gui, _('Export Catalog Directory'),
                    _('Select destination for %(title)s.%(fmt)s') % dict(
                        title=job.catalog_title, fmt=job.fmt.lower()))
            if export_dir:
                destination = os.path.join(export_dir, '%s.%s' % (
                    sanitize_file_name_unicode(job.catalog_title), job.fmt.lower()))
                try:
                    shutil.copyfile(job.catalog_file_path, destination)
                except EnvironmentError as err:
                    if getattr(err, 'errno', None) == errno.EACCES:  # Permission denied
                        import traceback
                        error_dialog(self, _('Permission denied'),
                                _('Could not open %s. Is it being used by another'
                                ' program?')%destination, det_msg=traceback.format_exc(),
                                show=True)
                        return
                    raise
Example #13
0
    def catalog_generated(self, job):
        if job.result:
            # Problems during catalog generation
            # jobs.results is a list - the first entry is the intended title for the dialog
            # Subsequent strings are error messages
            dialog_title = job.result.pop(0)
            if re.search('warning', job.result[0].lower()):
                msg = _("Catalog generation complete, with warnings.")
                warning_dialog(self.gui, dialog_title, msg, det_msg='\n'.join(job.result), show=True)
            else:
                job.result.append("Catalog generation terminated.")
                error_dialog(self.gui, dialog_title,'\n'.join(job.result),show=True)
                return

        if job.failed:
            return self.gui.job_exception(job)
        if dynamic.get('catalog_add_to_library', True):
            id = self.gui.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title)
            self.gui.library_view.model().beginResetModel(), self.gui.library_view.model().endResetModel()
            if job.catalog_sync:
                sync = dynamic.get('catalogs_to_be_synced', set([]))
                sync.add(id)
                dynamic.set('catalogs_to_be_synced', sync)
        self.gui.status_bar.show_message(_('Catalog generated.'), 3000)
        self.gui.sync_catalogs()
        if not dynamic.get('catalog_add_to_library', True) or job.fmt not in {'EPUB','MOBI', 'AZW3'}:
            export_dir = choose_dir(self.gui, _('Export Catalog Directory'),
                    _('Select destination for %(title)s.%(fmt)s') % dict(
                        title=job.catalog_title, fmt=job.fmt.lower()))
            if export_dir:
                destination = os.path.join(export_dir, '%s.%s' % (
                    sanitize_file_name_unicode(job.catalog_title), job.fmt.lower()))
                try:
                    shutil.copyfile(job.catalog_file_path, destination)
                except EnvironmentError as err:
                    if getattr(err, 'errno', None) == errno.EACCES:  # Permission denied
                        import traceback
                        error_dialog(self.gui, _('Permission denied'),
                                _('Could not open %s. Is it being used by another'
                                ' program?')%destination, det_msg=traceback.format_exc(),
                                show=True)
                        return
                    raise
Example #14
0
    def catalog_generated(self, job):
        if job.result:
            # Problems during catalog generation
            # jobs.results is a list - the first entry is the intended title for the dialog
            # Subsequent strings are error messages
            dialog_title = job.result.pop(0)
            if re.match('warning:', job.result[0].lower()):
                msg = _("Catalog generation complete, with warnings.")
                warning_dialog(self.gui,
                               dialog_title,
                               msg,
                               det_msg='\n'.join(job.result),
                               show=True)
            else:
                job.result.append("Catalog generation terminated.")
                error_dialog(self.gui,
                             dialog_title,
                             '\n'.join(job.result),
                             show=True)
                return

        if job.failed:
            return self.gui.job_exception(job)
        id = self.gui.library_view.model().add_catalog(job.catalog_file_path,
                                                       job.catalog_title)
        self.gui.library_view.model().reset()
        if job.catalog_sync:
            sync = dynamic.get('catalogs_to_be_synced', set([]))
            sync.add(id)
            dynamic.set('catalogs_to_be_synced', sync)
        self.gui.status_bar.show_message(_('Catalog generated.'), 3000)
        self.gui.sync_catalogs()
        if job.fmt not in ['EPUB', 'MOBI']:
            export_dir = choose_dir(
                self.gui, _('Export Catalog Directory'),
                _('Select destination for %(title)s.%(fmt)s') %
                dict(title=job.catalog_title, fmt=job.fmt.lower()))
            if export_dir:
                destination = os.path.join(
                    export_dir, '%s.%s' % (sanitize_file_name_unicode(
                        job.catalog_title), job.fmt.lower()))
                shutil.copyfile(job.catalog_file_path, destination)
Example #15
0
 def filename_button_clicked(self):
     try:
         path = choose_files(self,
                             'choose_category_icon',
                             _('Select Icon'),
                             filters=[('Images',
                                       ['png', 'gif', 'jpg', 'jpeg'])],
                             all_files=False,
                             select_only_single_file=True)
         if path:
             icon_path = path[0]
             icon_name = lower(
                 sanitize_file_name_unicode(
                     os.path.splitext(os.path.basename(icon_path))[0] +
                     '.png'))
             if icon_name not in self.icon_file_names:
                 self.icon_file_names.append(icon_name)
                 self.update_filename_box()
                 self.update_remove_button()
                 try:
                     p = QIcon(icon_path).pixmap(QSize(128, 128))
                     d = self.icon_folder
                     if not os.path.exists(os.path.join(d, icon_name)):
                         if not os.path.exists(d):
                             os.makedirs(d)
                         with open(os.path.join(d, icon_name), 'wb') as f:
                             f.write(pixmap_to_data(p, format='PNG'))
                 except:
                     import traceback
                     traceback.print_exc()
             if self.doing_multiple:
                 if icon_name not in self.rule_icon_files:
                     self.rule_icon_files.append(icon_name)
                 self.update_icon_filenames_in_box()
             else:
                 self.filename_box.setCurrentIndex(
                     self.filename_box.findText(icon_name))
             self.filename_box.adjustSize()
     except:
         import traceback
         traceback.print_exc()
     return
Example #16
0
def replace_file(container, name, path, basename, force_mt=None):
    dirname, base = name.rpartition('/')[0::2]
    nname = sanitize_file_name_unicode(basename)
    if dirname:
        nname = dirname + '/' + nname
    with open(path, 'rb') as src:
        if name != nname:
            count = 0
            b, e = nname.rpartition('.')[0::2]
            while container.exists(nname):
                count += 1
                nname = b + ('_%d.%s' % (count, e))
            rename_files(container, {name:nname})
            mt = force_mt or container.guess_type(nname)
            for itemid, q in container.manifest_id_map.iteritems():
                if q == nname:
                    for item in container.opf_xpath('//opf:manifest/opf:item[@href and @id="%s"]' % itemid):
                        item.set('media-type', mt)
        container.dirty(container.opf_name)
        with container.open(nname, 'wb') as dest:
            shutil.copyfileobj(src, dest)
Example #17
0
def replace_file(container, name, path, basename, force_mt=None):
    dirname, base = name.rpartition('/')[0::2]
    nname = sanitize_file_name_unicode(basename)
    if dirname:
        nname = dirname + '/' + nname
    with open(path, 'rb') as src:
        if name != nname:
            count = 0
            b, e = nname.rpartition('.')[0::2]
            while container.exists(nname):
                count += 1
                nname = b + ('_%d.%s' % (count, e))
            rename_files(container, {name:nname})
            mt = force_mt or container.guess_type(nname)
        for itemid, q in container.manifest_id_map.iteritems():
            if q == nname:
                for item in container.opf_xpath('//opf:manifest/opf:item[@href and @id="%s"]' % itemid):
                    item.set('media-type', mt)
        container.dirty(container.opf_name)
        with container.open(nname, 'wb') as dest:
            shutil.copyfileobj(src, dest)
Example #18
0
    def context_menu_handler(self, action=None, category=None, key=None, index=None, search_state=None):
        if not action:
            return
        try:
            if action == "set_icon":
                try:
                    path = choose_files(
                        self,
                        "choose_category_icon",
                        _("Change Icon for: %s") % key,
                        filters=[("Images", ["png", "gif", "jpg", "jpeg"])],
                        all_files=False,
                        select_only_single_file=True,
                    )
                    if path:
                        path = path[0]
                        p = QIcon(path).pixmap(QSize(128, 128))
                        d = os.path.join(config_dir, "tb_icons")
                        if not os.path.exists(d):
                            os.makedirs(d)
                        with open(os.path.join(d, "icon_" + sanitize_file_name_unicode(key) + ".png"), "wb") as f:
                            f.write(pixmap_to_data(p, format="PNG"))
                            path = os.path.basename(f.name)
                        self._model.set_custom_category_icon(key, unicode(path))
                        self.recount()
                except:
                    import traceback

                    traceback.print_exc()
                return
            if action == "clear_icon":
                self._model.set_custom_category_icon(key, None)
                self.recount()
                return

            if action == "edit_item":
                self.edit(index)
                return
            if action == "delete_item":
                self.tag_item_delete.emit(key, index.id, index.original_name)
                return
            if action == "open_editor":
                self.tags_list_edit.emit(category, key)
                return
            if action == "manage_categories":
                self.edit_user_category.emit(category)
                return
            if action == "search":
                self._toggle(index, set_to=search_state)
                return
            if action == "add_to_category":
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.all_children():
                        self.add_item_to_user_cat.emit(category, c.tag.original_name, c.tag.category)
                self.add_item_to_user_cat.emit(category, tag.original_name, tag.category)
                return
            if action == "add_subcategory":
                self.add_subcategory.emit(key)
                return
            if action == "search_category":
                self._toggle(index, set_to=search_state)
                return
            if action == "delete_user_category":
                self.delete_user_category.emit(key)
                return
            if action == "delete_search":
                self.model().db.saved_search_delete(key)
                self.rebuild_saved_searches.emit()
                return
            if action == "delete_item_from_user_category":
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.children:
                        self.del_item_from_user_cat.emit(key, c.tag.original_name, c.tag.category)
                self.del_item_from_user_cat.emit(key, tag.original_name, tag.category)
                return
            if action == "manage_searches":
                self.saved_search_edit.emit(category)
                return
            if action == "edit_author_sort":
                self.author_sort_edit.emit(self, index, True, False)
                return
            if action == "edit_author_link":
                self.author_sort_edit.emit(self, index, False, True)
                return

            reset_filter_categories = True
            if action == "hide":
                self.hidden_categories.add(category)
            elif action == "show":
                self.hidden_categories.discard(category)
            elif action == "categorization":
                changed = self.collapse_model != category
                self._model.collapse_model = category
                if changed:
                    reset_filter_categories = False
                    gprefs["tags_browser_partition_method"] = category
            elif action == "defaults":
                self.hidden_categories.clear()
            self.db.prefs.set("tag_browser_hidden_categories", list(self.hidden_categories))
            if reset_filter_categories:
                self._model.set_categories_filter(None)
            self._model.rebuild_node_tree()
        except:
            return
Example #19
0
    def rename_requested(self, name, location):
        LibraryDatabase = db_class()
        loc = location.replace("/", os.sep)
        base = os.path.dirname(loc)
        newname, ok = QInputDialog.getText(
            self.gui,
            _("Rename") + " " + name,
            "<p>"
            + _("Choose a new name for the library <b>%s</b>. ") % name
            + "<p>"
            + _("Note that the actual library folder will be renamed."),
            text=name,
        )
        newname = sanitize_file_name_unicode(unicode(newname))
        if not ok or not newname or newname == name:
            return
        newloc = os.path.join(base, newname)
        if os.path.exists(newloc):
            return error_dialog(
                self.gui, _("Already exists"), _("The folder %s already exists. Delete it first.") % newloc, show=True
            )
        if iswindows and len(newloc) > LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT:
            return error_dialog(
                self.gui,
                _("Too long"),
                _("Path to library too long. Must be less than" " %d characters.")
                % LibraryDatabase.WINDOWS_LIBRARY_PATH_LIMIT,
                show=True,
            )
        if not os.path.exists(loc):
            error_dialog(
                self.gui,
                _("Not found"),
                _(
                    "Cannot rename as no library was found at %s. "
                    "Try switching to this library first, then switch back "
                    "and retry the renaming."
                )
                % loc,
                show=True,
            )
            return
        try:
            os.rename(loc, newloc)
        except:
            import traceback

            det_msg = "Location: %r New Location: %r\n%s" % (loc, newloc, traceback.format_exc())
            error_dialog(
                self.gui,
                _("Rename failed"),
                _(
                    "Failed to rename the library at %s. "
                    "The most common cause for this is if one of the files"
                    " in the library is open in another program."
                )
                % loc,
                det_msg=det_msg,
                show=True,
            )
            return
        self.stats.rename(location, newloc)
        self.build_menus()
        self.gui.iactions["Copy To Library"].build_menus()
Example #20
0
 def sanitize_icon_file_name(self, icon_path):
     n = lower(sanitize_file_name_unicode(
                          os.path.splitext(
                                os.path.basename(icon_path))[0]+'.png'))
     return n.replace("'", '_')
Example #21
0
    def context_menu_handler(self,
                             action=None,
                             category=None,
                             key=None,
                             index=None,
                             search_state=None,
                             use_vl=None):
        if not action:
            return
        try:
            if action == 'set_icon':
                try:
                    path = choose_files(self,
                                        'choose_category_icon',
                                        _('Change icon for: %s') % key,
                                        filters=[
                                            ('Images',
                                             ['png', 'gif', 'jpg', 'jpeg'])
                                        ],
                                        all_files=False,
                                        select_only_single_file=True)
                    if path:
                        path = path[0]
                        p = QIcon(path).pixmap(QSize(128, 128))
                        d = os.path.join(config_dir, 'tb_icons')
                        if not os.path.exists(d):
                            os.makedirs(d)
                        with open(
                                os.path.join(
                                    d, 'icon_' +
                                    sanitize_file_name_unicode(key) + '.png'),
                                'wb') as f:
                            f.write(pixmap_to_data(p, format='PNG'))
                            path = os.path.basename(f.name)
                        self._model.set_custom_category_icon(
                            key, unicode(path))
                        self.recount()
                except:
                    import traceback
                    traceback.print_exc()
                return
            if action == 'clear_icon':
                self._model.set_custom_category_icon(key, None)
                self.recount()
                return

            if action == 'edit_item_no_vl':
                item = self.model().get_node(index)
                item.use_vl = False
                self.edit(index)
                return
            if action == 'edit_item_in_vl':
                item = self.model().get_node(index)
                item.use_vl = True
                self.edit(index)
                return
            if action == 'delete_item_in_vl':
                self.tag_item_delete.emit(key, index.id, index.original_name,
                                          self.model().get_book_ids_to_use())
                return
            if action == 'delete_item_no_vl':
                self.tag_item_delete.emit(key, index.id, index.original_name,
                                          None)
                return
            if action == 'open_editor':
                self.tags_list_edit.emit(category, key)
                return
            if action == 'manage_categories':
                self.edit_user_category.emit(category)
                return
            if action == 'search':
                self._toggle(index, set_to=search_state)
                return
            if action == "raw_search":
                from calibre.gui2.ui import get_gui
                get_gui().get_saved_search_text(search_name='search:' + key)
                return
            if action == 'add_to_category':
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.all_children():
                        self.add_item_to_user_cat.emit(category,
                                                       c.tag.original_name,
                                                       c.tag.category)
                self.add_item_to_user_cat.emit(category, tag.original_name,
                                               tag.category)
                return
            if action == 'add_subcategory':
                self.add_subcategory.emit(key)
                return
            if action == 'search_category':
                self._toggle(index, set_to=search_state)
                return
            if action == 'delete_user_category':
                self.delete_user_category.emit(key)
                return
            if action == 'delete_search':
                self.model().db.saved_search_delete(key)
                self.rebuild_saved_searches.emit()
                return
            if action == 'delete_item_from_user_category':
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.children:
                        self.del_item_from_user_cat.emit(
                            key, c.tag.original_name, c.tag.category)
                self.del_item_from_user_cat.emit(key, tag.original_name,
                                                 tag.category)
                return
            if action == 'manage_searches':
                self.saved_search_edit.emit(category)
                return
            if action == 'edit_author_sort':
                self.author_sort_edit.emit(self, index, True, False)
                return
            if action == 'edit_author_link':
                self.author_sort_edit.emit(self, index, False, True)
                return

            reset_filter_categories = True
            if action == 'hide':
                self.hidden_categories.add(category)
            elif action == 'show':
                self.hidden_categories.discard(category)
            elif action == 'categorization':
                changed = self.collapse_model != category
                self._model.collapse_model = category
                if changed:
                    reset_filter_categories = False
                    gprefs['tags_browser_partition_method'] = category
            elif action == 'defaults':
                self.hidden_categories.clear()
            self.db.new_api.set_pref('tag_browser_hidden_categories',
                                     list(self.hidden_categories))
            if reset_filter_categories:
                self._model.set_categories_filter(None)
            self._model.rebuild_node_tree()
        except:
            return
Example #22
0
 def sanitize_icon_file_name(self, icon_path):
     n = lower(sanitize_file_name_unicode(
                          os.path.splitext(
                                os.path.basename(icon_path))[0]+'.png'))
     return n.replace("'", '_')
Example #23
0
    def context_menu_handler(self, action=None, category=None,
                             key=None, index=None, search_state=None):
        if not action:
            return
        try:
            if action == 'set_icon':
                try:
                    path = choose_files(self, 'choose_category_icon',
                                _('Change Icon for: %s')%key, filters=[
                                ('Images', ['png', 'gif', 'jpg', 'jpeg'])],
                            all_files=False, select_only_single_file=True)
                    if path:
                        path = path[0]
                        p = QIcon(path).pixmap(QSize(128, 128))
                        d = os.path.join(config_dir, 'tb_icons')
                        if not os.path.exists(d):
                            os.makedirs(d)
                        with open(os.path.join(d, 'icon_'+
                            sanitize_file_name_unicode(key)+'.png'), 'wb') as f:
                            f.write(pixmap_to_data(p, format='PNG'))
                            path = os.path.basename(f.name)
                        self._model.set_custom_category_icon(key, unicode(path))
                        self.recount()
                except:
                    import traceback
                    traceback.print_exc()
                return
            if action == 'clear_icon':
                self._model.set_custom_category_icon(key, None)
                self.recount()
                return

            if action == 'edit_item':
                self.edit(index)
                return
            if action == 'delete_item':
                self.tag_item_delete.emit(key, index.id, index.original_name)
                return
            if action == 'open_editor':
                self.tags_list_edit.emit(category, key)
                return
            if action == 'manage_categories':
                self.edit_user_category.emit(category)
                return
            if action == 'search':
                self._toggle(index, set_to=search_state)
                return
            if action == 'add_to_category':
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.all_children():
                        self.add_item_to_user_cat.emit(category, c.tag.original_name,
                                               c.tag.category)
                self.add_item_to_user_cat.emit(category, tag.original_name,
                                               tag.category)
                return
            if action == 'add_subcategory':
                self.add_subcategory.emit(key)
                return
            if action == 'search_category':
                self._toggle(index, set_to=search_state)
                return
            if action == 'delete_user_category':
                self.delete_user_category.emit(key)
                return
            if action == 'delete_search':
                saved_searches().delete(key)
                self.rebuild_saved_searches.emit()
                return
            if action == 'delete_item_from_user_category':
                tag = index.tag
                if len(index.children) > 0:
                    for c in index.children:
                        self.del_item_from_user_cat.emit(key, c.tag.original_name,
                                               c.tag.category)
                self.del_item_from_user_cat.emit(key, tag.original_name, tag.category)
                return
            if action == 'manage_searches':
                self.saved_search_edit.emit(category)
                return
            if action == 'edit_author_sort':
                self.author_sort_edit.emit(self, index, True, False)
                return
            if action == 'edit_author_link':
                self.author_sort_edit.emit(self, index, False, True)
                return

            reset_filter_categories = True
            if action == 'hide':
                self.hidden_categories.add(category)
            elif action == 'show':
                self.hidden_categories.discard(category)
            elif action == 'categorization':
                changed = self.collapse_model != category
                self._model.collapse_model = category
                if changed:
                    reset_filter_categories = False
                    gprefs['tags_browser_partition_method'] = category
            elif action == 'defaults':
                self.hidden_categories.clear()
            self.db.prefs.set('tag_browser_hidden_categories', list(self.hidden_categories))
            if reset_filter_categories:
                self._model.set_categories_filter(None)
            self._model.rebuild_node_tree()
        except:
            return