Example #1
0
 def show_disclaimer(self):
     confirm(
         (
             "<p>"
             + _(
                 "Calibre helps you find the ebooks you want by searching "
                 "the websites of various commercial and public domain "
                 "book sources for you."
             )
             + "<p>"
             + _(
                 "Using the integrated search you can easily find which "
                 "store has the book you are looking for, at the best price. "
                 "You also get DRM status and other useful information."
             )
             + "<p>"
             + _(
                 "All transactions (paid or otherwise) are handled between "
                 "you and the book seller. "
                 "Calibre is not part of this process and any issues related "
                 "to a purchase should be directed to the website you are "
                 "buying from. Be sure to double check that any books you get "
                 "will work with your e-book reader, especially if the book you "
                 "are buying has "
                 '<a href="http://drmfree.calibre-ebook.com/about#drm">DRM</a>.'
             )
         ),
         "about_get_books_msg",
         parent=self.gui,
         show_cancel_button=False,
         confirm_msg=_("Show this message again"),
         pixmap="dialog_information.png",
         title=_("About Get Books"),
     )
Example #2
0
    def _add_formats(self, paths, ids):
        if len(ids) > 1 and not question_dialog(
                self.gui,
                _('Are you sure?'),
                _('Are you sure you want to add the same'
                  ' files to all %d books? If the format'
                  ' already exists for a book, it will be replaced.')%len(ids)):
            return

        db = self.gui.current_db
        if len(ids) == 1:
            formats = db.formats(ids[0], index_is_id=True)
            if formats:
                formats = {x.upper() for x in formats.split(',')}
                nformats = {f.rpartition('.')[-1].upper() for f in paths}
                override = formats.intersection(nformats)
                if override:
                    title = db.title(ids[0], index_is_id=True)
                    msg = ngettext(
                        'The {0} format will be replaced in the book {1}. Are you sure?',
                        'The {0} formats will be replaced in the book {1}. Are you sure?',
                        len(override)).format(', '.join(override), title)
                    if not confirm(msg, 'confirm_format_override_on_add', title=_('Are you sure?'), parent=self.gui):
                        return

        fmt_map = {os.path.splitext(fpath)[1][1:].upper():fpath for fpath in paths}

        for id_ in ids:
            for fmt, fpath in iteritems(fmt_map):
                if fmt:
                    db.add_format_with_hooks(id_, fmt, fpath, index_is_id=True,
                        notify=True)
        current_idx = self.gui.library_view.currentIndex()
        if current_idx.isValid():
            self.gui.library_view.model().current_changed(current_idx, current_idx)
Example #3
0
 def mark_groups_as_duplicate_exemptions(self, all_groups):
     can_exempt = self.duplicate_finder.check_can_mark_exemption(all_groups)
     if can_exempt:
         # Ensure that the selection is moved onto the current duplicate group
         duplicate_ids = self.duplicate_finder.get_current_duplicate_group_ids()
         self.gui.library_view.select_rows(duplicate_ids)
         exemption_type = 'books'
         if self.duplicate_finder.is_searching_for_authors():
             exemption_type = 'authors'
         dialog_name = 'find_duplicates_mark_all_groups' if all_groups else 'find_duplicates_mark_group'
         if not confirm('<p>' + _(
                         'This action will ensure that each of the %s in the group '
                         'are exempt from appearing together again in future.<p>'
                         'Are you <b>sure</b> you want to proceed?')%exemption_type,
                         dialog_name, self.gui):
             return
         if all_groups:
             self.duplicate_finder.mark_groups_as_duplicate_exemptions()
         else:
             self.duplicate_finder.mark_current_group_as_duplicate_exemptions()
     else:
         info_dialog(self.gui, _('No duplicates in group'),
                     _('There are no duplicates remaining in this group.'),
                     show=True, show_copy_button=False)
     self.update_actions_enabled()
Example #4
0
 def _save_settings(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     message = '<p>' + _('Are you sure you want to save this setting in this library for this plugin?') + '</p>' \
               + '<p>' + _('Any settings in other libraries or stored in a JSON file in your calibre plugins folder will not be touched.') + '</p>' \
               + '<p>' + _('You must restart calibre afterwards.') + '</p>'
     if not confirm(message, self.namespace+'_save_settings', self):
         return
     ns_prefix = self._get_ns_prefix()
     key = unicode(self.keys_list.currentItem().text())
     self.db.prefs.set_namespaced(self.namespace, key,
                                  self.db.prefs.raw_to_object(self.value_text.toPlainText()))
     d = info_dialog(self, 'Settings saved',
                     '<p>' + _('All settings for this plugin in this library have been saved.') + '</p>' \
                     + '<p>' + _('Please restart calibre now.') + '</p>',
                     show_copy_button=False)
     b = d.bb.addButton(_('Restart calibre now'), d.bb.AcceptRole)
     b.setIcon(QIcon(I('lt.png')))
     d.do_restart = False
     def rf():
         d.do_restart = True
     b.clicked.connect(rf)
     d.set_details('')
     d.exec_()
     b.clicked.disconnect()
     self.close()
     if d.do_restart:
         self.gui.quit(restart=True)
Example #5
0
    def start_download(self, request):
        if not self.gui:
            return

        url = unicode(request.url().toString(NO_URL_FORMATTING))
        cf = self.get_cookies()

        filename = get_download_filename(url, cf)
        ext = os.path.splitext(filename)[1][1:].lower()
        filename = ascii_filename(filename[:60] + '.' + ext)
        if ext not in BOOK_EXTENSIONS:
            if ext == 'acsm':
                from calibre.gui2.dialogs.confirm_delete import confirm
                if not confirm('<p>' + _('This ebook is a DRMed EPUB file.  '
                          'You will be prompted to save this file to your '
                          'computer. Once it is saved, open it with '
                          '<a href="https://www.adobe.com/products/digitaleditions/">'
                          'Adobe Digital Editions</a> (ADE).<p>ADE, in turn '
                          'will download the actual ebook, which will be a '
                          '.epub file. You can add this book to calibre '
                          'using "Add Books" and selecting the file from '
                          'the ADE library folder.'),
                          'acsm_download', self):
                    return
            name = choose_save_file(self, 'web-store-download-unknown', _('File is not a supported ebook type. Save to disk?'), initial_filename=filename)
            if name:
                self.gui.download_ebook(url, cf, name, name, False, create_browser=self.create_browser)
        else:
            show_download_info(filename, self)
            self.gui.download_ebook(url, cf, filename, tags=self.tags, create_browser=self.create_browser)
Example #6
0
 def confirm_large_merge(self, num):
     if num < 5:
         return True
     return confirm('<p>'+_(
         'You are about to merge very many ({}) books. '
         'Are you <b>sure</b> you want to proceed?').format(num) + '</p>',
         'merge_too_many_books', self.gui)
 def _clear_settings(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     message = '<p>Are you sure you want to clear your settings in this library for this plugin?</p>' \
               '<p>Any settings in other libraries or stored in a JSON file in your calibre plugins ' \
               'folder will not be touched.</p>' \
               '<p>You must restart calibre afterwards.</p>'
     if not confirm(message, self.namespace+'_clear_settings', self):
         return
     ns_prefix = self._get_ns_prefix()
     keys = [k for k in self.db.prefs.iterkeys() if k.startswith(ns_prefix)]
     for k in keys:
         del self.db.prefs[k]
     self._populate_settings()
     d = info_dialog(self, 'Settings deleted',
                 '<p>All settings for this plugin in this library have been cleared.</p>'
                 '<p>Please restart calibre now.</p>',
                 show_copy_button=False)
     b = d.bb.addButton(_('Restart calibre now'), d.bb.AcceptRole)
     b.setIcon(QIcon(I('lt.png')))
     d.do_restart = False
     def rf():
         d.do_restart = True
     b.clicked.connect(rf)
     d.set_details('')
     d.exec_()
     b.clicked.disconnect()
     self.close()
     if d.do_restart:
         self.gui.quit(restart=True)
Example #8
0
    def start_download(self, request):
        if not self.gui:
            return

        url = unicode(request.url().toString())
        cf = self.get_cookies()

        filename = get_download_filename(url, cf)
        ext = os.path.splitext(filename)[1][1:].lower()
        filename = ascii_filename(filename[:60] + '.' + ext)
        if ext not in BOOK_EXTENSIONS:
            if ext == 'acsm':
                from calibre.gui2.dialogs.confirm_delete import confirm
                if not confirm('<p>' + _('This ebook is a DRMed EPUB file.  '
                          'You will be prompted to save this file to your '
                          'computer. Once it is saved, open it with '
                          '<a href="http://www.adobe.com/products/digitaleditions/">'
                          'Adobe Digital Editions</a> (ADE).<p>ADE, in turn '
                          'will download the actual ebook, which will be a '
                          '.epub file. You can add this book to calibre '
                          'using "Add Books" and selecting the file from '
                          'the ADE library folder.'),
                          'acsm_download', self):
                    return
            home = os.path.expanduser('~')
            name = QFileDialog.getSaveFileName(self,
                _('File is not a supported ebook type. Save to disk?'),
                os.path.join(home, filename),
                '*.*')
            if name:
                name = unicode(name)
                self.gui.download_ebook(url, cf, name, name, False)
        else:
            self.gui.download_ebook(url, cf, filename, tags=self.tags)
Example #9
0
 def delete_books(self, *args):
     '''
     Delete selected books from device or library.
     '''
     view = self.gui.current_view()
     rows = view.selectionModel().selectedRows()
     if not rows or len(rows) == 0:
         return
     # Library view is visible.
     if self.gui.stack.currentIndex() == 0:
         to_delete_ids = [view.model().id(r) for r in rows]
         self.do_library_delete(to_delete_ids)
     # Device view is visible.
     else:
         if self.gui.stack.currentIndex() == 1:
             view = self.gui.memory_view
         elif self.gui.stack.currentIndex() == 2:
             view = self.gui.card_a_view
         else:
             view = self.gui.card_b_view
         paths = view.model().paths(rows)
         ids = view.model().indices(rows)
         if not confirm('<p>'+_('The %d selected book(s) will be '
                                '<b>permanently deleted</b> '
                                'from your device. Are you sure?')%len(paths)
                             +'</p>', 'device_delete_books', self.gui):
             return
         job = self.gui.remove_paths(paths)
         self.delete_memory[job] = (paths, view.model())
         view.model().mark_for_deletion(job, ids, rows_are_ids=True)
         self.gui.status_bar.show_message(_('Deleting books from device.'), 1000)
Example #10
0
    def delete_tags(self):
        deletes = self.table.selectedItems()
        if not deletes:
            error_dialog(self, _('No items selected'),
                         _('You must select at least one item from the list.')).exec_()
            return

        to_del = []
        to_undel = []
        for item in deletes:
            if item.is_deleted:
                to_undel.append(item)
            else:
                to_del.append(item)
        if to_del:
            ct = ', '.join([unicode_type(item.text()) for item in to_del])
            if not confirm(
                '<p>'+_('Are you sure you want to delete the following items?')+'<br>'+ct,
                'tag_list_editor_delete'):
                return
        if to_undel:
            ct = ', '.join([unicode_type(item.text()) for item in to_undel])
            if not confirm(
                '<p>'+_('Are you sure you want to undelete the following items?')+'<br>'+ct,
                'tag_list_editor_undelete'):
                return
        row = self.table.row(deletes[0])
        for item in deletes:
            if item.is_deleted:
                item.set_is_deleted(False)
                self.to_delete.discard(int(item.data(Qt.UserRole)))
                orig = self.table.item(item.row(), 2)
                self.table.blockSignals(True)
                orig.setData(Qt.DisplayRole, '')
                self.table.blockSignals(False)
            else:
                id = int(item.data(Qt.UserRole))
                self.to_delete.add(id)
                item.set_is_deleted(True)
                orig = self.table.item(item.row(), 2)
                self.table.blockSignals(True)
                orig.setData(Qt.DisplayRole, item.initial_text())
                self.table.blockSignals(False)
        if row >= self.table.rowCount():
            row = self.table.rowCount() - 1
        if row >= 0:
            self.table.scrollToItem(self.table.item(row, 0))
Example #11
0
 def _edit_settings(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     message = '<p>' + _('Are you sure you want to edit settings in this library for this plugin?') + '</p>' \
               + '<p>' + _('The FanFicFare team does not support hand edited configurations.') + '</p>'
     if confirm(message, self.namespace+'_edit_settings', self):
         self.save_button.setEnabled(True)
         self.edit_button.setEnabled(False)
         self.value_text.setReadOnly(False)
 def remove_vl_triggered(self, name=None):
     if not confirm(
         _("Are you sure you want to remove the virtual library <b>{0}</b>?").format(name),
         "confirm_vl_removal",
         parent=self,
     ):
         return
     self._remove_vl(name, reapply=True)
Example #13
0
 def reject(self):
     if self.next_called and not confirm(_(
         'All reviewed changes will be lost! Are you sure you want to Cancel?'),
         'confirm-metadata-diff-dialog-cancel'):
         return
     gprefs.set('diff_dialog_geom', bytearray(self.saveGeometry()))
     self.compare_widget.save_comments_controls_state()
     super(CompareMany, self).reject()
Example #14
0
 def _edit_settings(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     message = '<p>' + _('Are you sure you want to edit settings in this library for this plugin?') + '</p>' \
               + '<p>' + _('The FanFicFare team does not support hand edited configurations.') + '</p>'
     if confirm(message, self.namespace + '_edit_settings', self):
         self.save_button.setEnabled(True)
         self.edit_button.setEnabled(False)
         self.value_text.setReadOnly(False)
Example #15
0
 def remove_vl_triggered(self, name=None):
     if not confirm(_(
             'Are you sure you want to remove the virtual library <b>{0}</b>?'
     ).format(name),
                    'confirm_vl_removal',
                    parent=self):
         return
     self._remove_vl(name, reapply=True)
Example #16
0
    def do_library_delete(self, to_delete_ids):
        view = self.gui.current_view()
        next_id = view.next_id
        # Ask the user if they want to delete the book from the library or device if it is in both.
        if self.gui.device_manager.is_device_present:
            on_device = False
            on_device_ids = self._get_selected_ids()
            for id in on_device_ids:
                res = self.gui.book_on_device(id)
                if res[0] or res[1] or res[2]:
                    on_device = True
                if on_device:
                    break
            if on_device:
                loc = confirm_location(
                    '<p>' +
                    _('Some of the selected books are on the attached device. '
                      '<b>Where</b> do you want the selected files deleted from?'
                      ), self.gui)
                if not loc:
                    return
                elif loc == 'dev':
                    self.remove_matching_books_from_device()
                    return
                elif loc == 'both':
                    self.remove_matching_books_from_device()
        # The following will run if the selected books are not on a connected device.
        # The user has selected to delete from the library or the device and library.
        if not confirm(
                '<p>' + ngettext(
                    'The selected book will be <b>permanently deleted</b> and the files '
                    'removed from your calibre library. Are you sure?',
                    'The {} selected books will be <b>permanently deleted</b> and the files '
                    'removed from your calibre library. Are you sure?',
                    len(to_delete_ids)).format(len(to_delete_ids)),
                'library_delete_books', self.gui):
            return
        if len(to_delete_ids) < 5:
            try:
                view.model().delete_books_by_id(to_delete_ids)
            except IOError as err:
                if err.errno == errno.EACCES:
                    import traceback
                    fname = getattr(err, 'filename', 'file') or 'file'
                    return error_dialog(
                        self.gui,
                        _('Permission denied'),
                        _('Could not access %s. Is it being used by another'
                          ' program? Click "Show details" for more information.'
                          ) % fname,
                        det_msg=traceback.format_exc(),
                        show=True)

            self.library_ids_deleted2(to_delete_ids, next_id=next_id)
        else:
            self.__md = MultiDeleter(
                self.gui, to_delete_ids,
                partial(self.library_ids_deleted2, next_id=next_id))
Example #17
0
    def add_empty_format(self, format_):
        if self.gui.stack.currentIndex() != 0:
            return
        view = self.gui.library_view
        rows = view.selectionModel().selectedRows()
        if not rows:
            return error_dialog(self.gui,
                                _('No books selected'),
                                _('Cannot add files as no books are selected'),
                                show=True)

        ids = [view.model().id(r) for r in rows]

        if len(ids) > 1 and not question_dialog(
                self.gui, _('Are you sure?'),
                _('Are you sure you want to add the same'
                  ' empty file to all %d books? If the format'
                  ' already exists for a book, it will be replaced.') %
                len(ids)):
            return

        db = self.gui.library_view.model().db
        if len(ids) == 1:
            formats = db.formats(ids[0], index_is_id=True)
            if formats:
                formats = {x.lower() for x in formats.split(',')}
                if format_ in formats:
                    title = db.title(ids[0], index_is_id=True)
                    msg = _(
                        'The {0} format will be replaced in the book {1}. Are you sure?'
                    ).format(format_, title)
                    if not confirm(msg,
                                   'confirm_format_override_on_add',
                                   title=_('Are you sure?'),
                                   parent=self.gui):
                        return

        for id_ in ids:
            from calibre.ebooks.oeb.polish.create import create_book
            pt = PersistentTemporaryFile(suffix='.' + format_)
            pt.close()
            try:
                mi = db.new_api.get_metadata(id_,
                                             get_cover=False,
                                             get_user_categories=False,
                                             cover_as_data=False)
                create_book(mi, pt.name, fmt=format_)
                db.add_format_with_hooks(id_,
                                         format_,
                                         pt.name,
                                         index_is_id=True,
                                         notify=True)
            finally:
                os.remove(pt.name)

        current_idx = self.gui.library_view.currentIndex()
        if current_idx.isValid():
            view.model().current_changed(current_idx, current_idx)
Example #18
0
 def del_category(self):
     if self.current_cat_name is not None:
         if not confirm('<p>'+_('The current tag category will be '
                        '<b>permanently deleted</b>. Are you sure?') +
                        '</p>', 'tag_category_delete', self):
             return
         del self.categories[self.current_cat_name]
         self.current_cat_name = None
         self.category_box.removeItem(self.category_box.currentIndex())
Example #19
0
 def del_search(self):
     if self.current_search_name is not None:
         if not confirm('<p>'+_('The current saved search will be '
                        '<b>permanently deleted</b>. Are you sure?')
                     +'</p>', 'saved_search_editor_delete', self):
             return
         del self.searches[self.current_search_name]
         self.current_search_name = None
         self.search_name_box.removeItem(self.search_name_box.currentIndex())
Example #20
0
 def del_search(self):
     if self.current_search_name is not None:
         if not confirm('<p>'+_('The current saved search will be '
                        '<b>permanently deleted</b>. Are you sure?')
                     +'</p>', 'saved_search_editor_delete', self):
             return
         del self.searches[self.current_search_name]
         self.current_search_name = None
         self.search_name_box.removeItem(self.search_name_box.currentIndex())
Example #21
0
 def del_category(self):
     if self.current_cat_name is not None:
         if not confirm('<p>'+_('The current tag category will be '
                        '<b>permanently deleted</b>. Are you sure?')
                     +'</p>', 'tag_category_delete', self):
             return
         del self.categories[self.current_cat_name]
         self.current_cat_name = None
         self.category_box.removeItem(self.category_box.currentIndex())
Example #22
0
 def delete_annotations(self, ids):
     if confirm(ngettext(
         'Are you sure you want to <b>permanently</b> delete this annotation?',
         'Are you sure you want to <b>permanently</b> delete these {} annotations?',
         len(ids)).format(len(ids)), 'delete-annotation-from-browse', parent=self
     ):
         db = current_db()
         db.delete_annotations(ids)
         self.browse_panel.refresh()
Example #23
0
    def add_formats(self, *args):
        if self.gui.stack.currentIndex() != 0:
            return
        view = self.gui.library_view
        rows = view.selectionModel().selectedRows()
        if not rows:
            return error_dialog(self.gui,
                                _('No books selected'),
                                _('Cannot add files as no books are selected'),
                                show=True)
        ids = [view.model().id(r) for r in rows]

        if len(ids) > 1 and not question_dialog(
                self.gui, _('Are you sure'),
                _('Are you sure you want to add the same'
                  ' files to all %d books? If the format'
                  ' already exists for a book, it will be replaced.') %
                len(ids)):
            return

        books = choose_files(self.gui,
                             'add formats dialog dir',
                             _('Select book files'),
                             filters=get_filters())
        if not books:
            return

        db = view.model().db
        if len(ids) == 1:
            formats = db.formats(ids[0], index_is_id=True)
            if formats:
                formats = {x.upper() for x in formats.split(',')}
                nformats = {f.rpartition('.')[-1].upper() for f in books}
                override = formats.intersection(nformats)
                if override:
                    title = db.title(ids[0], index_is_id=True)
                    msg = _(
                        'The {0} format(s) will be replaced in the book {1}. Are you sure?'
                    ).format(', '.join(override), title)
                    if not confirm(msg,
                                   'confirm_format_override_on_add',
                                   title=_('Are you sure'),
                                   parent=self.gui):
                        return

        for id_ in ids:
            for fpath in books:
                fmt = os.path.splitext(fpath)[1][1:].upper()
                if fmt:
                    db.add_format_with_hooks(id_,
                                             fmt,
                                             fpath,
                                             index_is_id=True,
                                             notify=True)
        current_idx = self.gui.library_view.currentIndex()
        if current_idx.isValid():
            view.model().current_changed(current_idx, current_idx)
Example #24
0
 def del_search(self):
     n = self.current_search_name
     if n is not None:
         if not confirm(
                 '<p>' + _('The current saved search will be '
                           '<b>permanently deleted</b>. Are you sure?') +
                 '</p>', 'saved_search_editor_delete', self):
             return
         self.slist.takeItem(self.slist.currentRow())
         del self.searches[n]
Example #25
0
 def reject_all_remaining(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     if not confirm(_('Are you sure you want to reject all %d remaining results?') % len(self.ids), 'confirm_metadata_review_reject', parent=self):
         return
     self.next_item(False)
     for id_ in self.ids:
         oldmi, newmi = self.get_metadata(id_)
         self.accepted[id_] = (False, None)
     self.ids = []
     self.accept()
Example #26
0
 def reject_all_remaining(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     if not confirm(_('Are you sure you want to reject all %d remaining results?') % len(self.ids), 'confirm_metadata_review_reject', parent=self):
         return
     self.next_item(False)
     for id_ in self.ids:
         oldmi, newmi = self.get_metadata(id_)
         self.accepted[id_] = (False, None)
     self.ids = []
     self.accept()
Example #27
0
    def modify_plugin(self, op=''):
        index = self.plugin_view.currentIndex()
        if index.isValid():
            if not index.parent().isValid():
                name = str(index.data() or '')
                return error_dialog(self, _('Error'), '<p>'+
                        _('Select an actual plugin under <b>%s</b> to customize')%name,
                        show=True, show_copy_button=False)

            plugin = self._plugin_model.index_to_plugin(index)
            if op == 'toggle':
                if not plugin.can_be_disabled:
                    info_dialog(self, _('Plugin cannot be disabled'),
                                 _('Disabling the plugin %s is not allowed')%plugin.name, show=True, show_copy_button=False)
                    return
                if is_disabled(plugin):
                    enable_plugin(plugin)
                else:
                    disable_plugin(plugin)
                self._plugin_model.refresh_plugin(plugin)
                self.changed_signal.emit()
            if op == 'customize':
                if not plugin.is_customizable():
                    info_dialog(self, _('Plugin not customizable'),
                        _('Plugin: %s does not need customization')%plugin.name).exec_()
                    return
                self.changed_signal.emit()
                from calibre.customize import InterfaceActionBase
                if isinstance(plugin, InterfaceActionBase) and not getattr(plugin,
                        'actual_iaction_plugin_loaded', False):
                    return error_dialog(self, _('Must restart'),
                            _('You must restart calibre before you can'
                                ' configure the <b>%s</b> plugin')%plugin.name, show=True)
                if plugin.do_user_config(self.gui):
                    self._plugin_model.refresh_plugin(plugin)
            elif op == 'remove':
                if not confirm('<p>' +
                    _('Are you sure you want to remove the plugin: %s?')%
                    '<b>{0}</b>'.format(plugin.name),
                    'confirm_plugin_removal_msg', parent=self):
                    return

                msg = _('Plugin <b>{0}</b> successfully removed. You will have'
                        ' to restart calibre for it to be completely removed.').format(plugin.name)
                if remove_plugin(plugin):
                    self._plugin_model.beginResetModel()
                    self._plugin_model.populate()
                    self._plugin_model.endResetModel()
                    self.changed_signal.emit()
                    info_dialog(self, _('Success'), msg, show=True,
                            show_copy_button=False)
                else:
                    error_dialog(self, _('Cannot remove builtin plugin'),
                         plugin.name + _(' cannot be removed. It is a '
                         'builtin plugin. Try disabling it instead.')).exec_()
Example #28
0
    def modify_plugin(self, op=''):
        index = self.plugin_view.currentIndex()
        if index.isValid():
            if not index.parent().isValid():
                name = unicode(index.data() or '')
                return error_dialog(self, _('Error'), '<p>'+
                        _('Select an actual plugin under <b>%s</b> to customize')%name,
                        show=True, show_copy_button=False)

            plugin = self._plugin_model.index_to_plugin(index)
            if op == 'toggle':
                if not plugin.can_be_disabled:
                    info_dialog(self, _('Plugin cannot be disabled'),
                                 _('Disabling the plugin %s is not allowed')%plugin.name, show=True, show_copy_button=False)
                    return
                if is_disabled(plugin):
                    enable_plugin(plugin)
                else:
                    disable_plugin(plugin)
                self._plugin_model.refresh_plugin(plugin)
                self.changed_signal.emit()
            if op == 'customize':
                if not plugin.is_customizable():
                    info_dialog(self, _('Plugin not customizable'),
                        _('Plugin: %s does not need customization')%plugin.name).exec_()
                    return
                self.changed_signal.emit()
                from calibre.customize import InterfaceActionBase
                if isinstance(plugin, InterfaceActionBase) and not getattr(plugin,
                        'actual_iaction_plugin_loaded', False):
                    return error_dialog(self, _('Must restart'),
                            _('You must restart calibre before you can'
                                ' configure the <b>%s</b> plugin')%plugin.name, show=True)
                if plugin.do_user_config(self.gui):
                    self._plugin_model.refresh_plugin(plugin)
            elif op == 'remove':
                if not confirm('<p>' +
                    _('Are you sure you want to remove the plugin: %s?')%
                    '<b>{0}</b>'.format(plugin.name),
                    'confirm_plugin_removal_msg', parent=self):
                    return

                msg = _('Plugin <b>{0}</b> successfully removed. You will have'
                        ' to restart calibre for it to be completely removed.').format(plugin.name)
                if remove_plugin(plugin):
                    self._plugin_model.beginResetModel()
                    self._plugin_model.populate()
                    self._plugin_model.endResetModel()
                    self.changed_signal.emit()
                    info_dialog(self, _('Success'), msg, show=True,
                            show_copy_button=False)
                else:
                    error_dialog(self, _('Cannot remove builtin plugin'),
                         plugin.name + _(' cannot be removed. It is a '
                         'builtin plugin. Try disabling it instead.')).exec_()
Example #29
0
 def del_search(self):
     n = self.current_search_name
     if n is not None:
         if not confirm(
             '<p>' + _(
                 'The current saved search will be '
                 '<b>permanently deleted</b>. Are you sure?') + '</p>',
             'saved_search_editor_delete', self):
             return
         self.slist.takeItem(self.slist.currentRow())
         del self.searches[n]
 def del_search(self):
     if self.current_search_name is not None:
         if not confirm(
             "<p>" + _("The current saved search will be " "<b>permanently deleted</b>. Are you sure?") + "</p>",
             "saved_search_editor_delete",
             self,
         ):
             return
         del self.searches[self.current_search_name]
         self.current_search_name = None
         self.search_name_box.removeItem(self.search_name_box.currentIndex())
Example #31
0
 def generate_cover(self, *args):
     book_id = self.data.get('id')
     if book_id is None:
         return
     from calibre.gui2.ui import get_gui
     mi = get_gui().current_db.new_api.get_metadata(book_id)
     if not mi.has_cover or confirm(
             _('Are you sure you want to replace the cover? The existing cover will be permanently lost.'), 'book_details_generate_cover'):
         from calibre.ebooks.covers import generate_cover
         cdata = generate_cover(mi)
         self.update_cover(cdata=cdata)
Example #32
0
 def show_disclaimer(self):
     confirm(('<p>' +
         _('Calibre helps you find the ebooks you want by searching '
         'the websites of various commercial and public domain '
         'book sources for you.') +
         '<p>' +
         _('Using the integrated search you can easily find which '
         'store has the book you are looking for, at the best price. '
         'You also get DRM status and other useful information.') + '<p>' +
         _('All transactions (paid or otherwise) are handled between '
         'you and the book seller. '
         'Calibre is not part of this process and any issues related '
         'to a purchase should be directed to the website you are '
         'buying from. Be sure to double check that any books you get '
         'will work with your e-book reader, especially if the book you '
         'are buying has '
         '<a href="http://drmfree.calibre-ebook.com/about#drm">DRM</a>.'
         )), 'about_get_books_msg',
         parent=self.gui, show_cancel_button=False,
         confirm_msg=_('Show this message again'),
         pixmap='dialog_information.png', title=_('About Get Books'))
Example #33
0
 def show_disclaimer(self):
     confirm(('<p>' +
         _('calibre helps you find the e-books you want by searching '
         'the websites of various commercial and public domain '
         'book sources for you.') +
         '<p>' +
         _('Using the integrated search you can easily find which '
         'store has the book you are looking for, at the best price. '
         'You also get DRM status and other useful information.') + '<p>' +
         _('All transactions (paid or otherwise) are handled between '
         'you and the book seller. '
         'calibre is not part of this process and any issues related '
         'to a purchase should be directed to the website you are '
         'buying from. Be sure to double check that any books you get '
         'will work with your e-book reader, especially if the book you '
         'are buying has '
         '<a href="https://drmfree.calibre-ebook.com/about#drm">DRM</a>.'
         )), 'about_get_books_msg',
         parent=self.gui, show_cancel_button=False,
         confirm_msg=_('Show this message again'),
         pixmap='dialog_information.png', title=_('About Get books'))
Example #34
0
 def files_dropped_on_book(self, event, paths, cid=None, do_confirm=True):
     accept = False
     if self.gui.current_view() is not self.gui.library_view:
         return
     db = self.gui.library_view.model().db
     cover_changed = False
     current_idx = self.gui.library_view.currentIndex()
     if cid is None:
         if not current_idx.isValid():
             return
         cid = db.id(current_idx.row()) if cid is None else cid
     formats = []
     from calibre.gui2.dnd import image_extensions
     image_exts = set(image_extensions()) - set(tweaks['cover_drop_exclude'])
     if iswindows:
         from calibre.gui2.add import resolve_windows_links
         paths = list(resolve_windows_links(paths, hwnd=int(self.gui.effectiveWinId())))
     for path in paths:
         ext = os.path.splitext(path)[1].lower()
         if ext:
             ext = ext[1:]
         if ext in image_exts:
             pmap = QPixmap()
             pmap.load(path)
             if not pmap.isNull():
                 accept = True
                 db.set_cover(cid, pmap)
                 cover_changed = True
         else:
             formats.append((ext, path))
             accept = True
     if accept and event is not None:
         event.accept()
     add_as_book = False
     if do_confirm and formats:
         ok, add_as_book = confirm(
             _('You have dropped some files onto the book <b>%s</b>. This will'
               ' add or replace the files for this book. Do you want to proceed?') % db.title(cid, index_is_id=True),
             'confirm_drop_on_book', parent=self.gui,
             extra_button=ngettext('Add as new book', 'Add as new books', len(formats)))
         if ok and add_as_book:
             add_as_book = [path for ext, path in formats]
         if not ok or add_as_book:
             formats = []
     for ext, path in formats:
         db.add_format_with_hooks(cid, ext, path, index_is_id=True)
     if current_idx.isValid():
         self.gui.library_view.model().current_changed(current_idx, current_idx)
     if cover_changed:
         self.gui.refresh_cover_browser()
     if add_as_book:
         self.files_dropped(add_as_book)
Example #35
0
 def rename_requested(self, oldname, newname):
     self.commit_all_editors_to_container()
     if guess_type(oldname) != guess_type(newname):
         args = os.path.splitext(oldname) + os.path.splitext(newname)
         if not confirm(
             _(
                 "You are changing the file type of {0}<b>{1}</b> to {2}<b>{3}</b>."
                 " Doing so can cause problems, are you sure?"
             ).format(*args),
             "confirm-filetype-change",
             parent=self.gui,
             title=_("Are you sure?"),
             config_set=tprefs,
         ):
             return
     if urlnormalize(newname) != newname:
         if not confirm(
             _(
                 "The name you have chosen {0} contains special characters, internally"
                 " it will look like: {1}Try to use only the English alphabet [a-z], numbers [0-9],"
                 " hyphens and underscores for file names. Other characters can cause problems for "
                 " different ebook viewers. Are you sure you want to proceed?"
             ).format("<pre>%s</pre>" % newname, "<pre>%s</pre>" % urlnormalize(newname)),
             "confirm-urlunsafe-change",
             parent=self.gui,
             title=_("Are you sure?"),
             config_set=tprefs,
         ):
             return
     self.add_savepoint(_("Rename %s") % oldname)
     name_map = {oldname: newname}
     self.gui.blocking_job(
         "rename_file",
         _("Renaming and updating links..."),
         partial(self.rename_done, name_map),
         rename_files,
         current_container(),
         name_map,
     )
Example #36
0
 def new_books(self):
     if not self.lines_table.selected_all_have_toc():
         if not confirm("<p><b>"+_('Missing Title(s)')+"</b></p><p>"+
                        ("</p><p>").join([_("Some selected sections don't have a Table of Contents text."),
                                          _("If you continue, those sections will be included with the last prior section that did have a Table of Contents text."),
                                          _("If you cancel, you can go back and add Table of Contents entries.")+" "+
                                          _("Double click to edit the Table of Contents entry for a section.")])
                        +"</p>",
                        'epubsplit_missing_tocs_warning_again',
                        self.gui):
             return
     # return a list of lists of linenums
     self.do_splits_fn(self.lines_table.get_selected_tocs())
Example #37
0
 def remove_highlight(self):
     highlights = tuple(self.highlights.selected_highlights)
     if not highlights:
         return self.no_selected_highlight()
     if confirm(ngettext(
             'Are you sure you want to delete this highlight permanently?',
             'Are you sure you want to delete all {} highlights permanently?',
             len(highlights)).format(len(highlights)),
                'delete-highlight-from-viewer',
                parent=self,
                config_set=vprefs):
         for h in highlights:
             self.request_highlight_action.emit(h['uuid'], 'delete')
Example #38
0
    def remove_format_by_id(self, book_id, fmt):
        title = self.gui.current_db.title(book_id, index_is_id=True)
        if not confirm('<p>'+(_(
            'The %(fmt)s format will be <b>permanently deleted</b> from '
            '%(title)s. Are you sure?')%dict(fmt=fmt, title=title)) +
                       '</p>', 'library_delete_specific_format', self.gui):
            return

        self.gui.library_view.model().db.remove_format(book_id, fmt,
                index_is_id=True, notify=False)
        self.gui.library_view.model().refresh_ids([book_id])
        self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
                self.gui.library_view.currentIndex())
        self.gui.tags_view.recount_with_position_based_index()
 def createEditor(self, parent, option, index):
     item = self.table.item(index.row(), 0)
     if index.column() == 0:
         item = self.table.item(index.row(), 0)
         if item.is_deleted:
             return None
         return QItemDelegate.createEditor(self, parent, option, index)
     if not confirm(_('Do you want to undo your changes?'),
                    'tag_list_editor_undo'):
         return
     item.setText(item.initial_text())
     self.table.blockSignals(True)
     self.table.item(index.row(), 2).setData(Qt.DisplayRole, '')
     self.table.blockSignals(False)
Example #40
0
    def download_finished(self, download_id):
        self.central.download_progress.remove_item(download_id)
        download_item = self.download_data.pop(download_id)
        path = download_item.path()
        fname = os.path.basename(path)
        if download_item.state() == download_item.DownloadInterrupted:
            error_dialog(self, _('Download failed'), _(
                'Download of {0} failed with error: {1}').format(fname, download_item.interruptReasonString()), show=True)
            return
        ext = fname.rpartition('.')[-1].lower()
        if ext not in BOOK_EXTENSIONS:
            if ext == 'acsm':
                if not confirm('<p>' + _(
                    'This e-book is a DRMed EPUB file.  '
                    'You will be prompted to save this file to your '
                    'computer. Once it is saved, open it with '
                    '<a href="https://www.adobe.com/solutions/ebook/digital-editions.html">'
                    'Adobe Digital Editions</a> (ADE).<p>ADE, in turn '
                    'will download the actual e-book, which will be a '
                    '.epub file. You can add this book to calibre '
                    'using "Add Books" and selecting the file from '
                    'the ADE library folder.'),
                    'acsm_download', self):
                    return
            name = choose_save_file(self, 'web-store-download-unknown', _(
                'File is not a supported e-book type. Save to disk?'), initial_filename=fname)
            if name:
                shutil.copyfile(path, name)
                os.remove(path)
            return
        t = RC(print_error=False)
        t.start()
        t.join(3.0)
        if t.conn is None:
            error_dialog(self, _('No running calibre'), _(
                'No running calibre instance found. Please start calibre before trying to'
                ' download books.'), show=True)
            return
        tags = self.data['tags']
        if isinstance(tags, string_or_bytes):
            tags = list(filter(None, [x.strip() for x in tags.split(',')]))
        data = json.dumps({'path': path, 'tags': tags})
        if not isinstance(data, bytes):
            data = data.encode('utf-8')
        t.conn.send(b'web-store:' + data)
        t.conn.close()

        info_dialog(self, _('Download completed'), _(
            'Download of {0} has been completed, the book was added to'
            ' your calibre library').format(fname), show=True)
Example #41
0
 def sort_css(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     if confirm(_('Sorting CSS rules can in rare cases change the effective styles applied to the book.'
                  ' Are you sure you want to proceed?'), 'edit-book-confirm-sort-css', parent=self, config_set=tprefs):
         c = self.textCursor()
         c.beginEditBlock()
         c.movePosition(c.Start), c.movePosition(c.End, c.KeepAnchor)
         text = unicode_type(c.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0')
         from calibre.ebooks.oeb.polish.css import sort_sheet
         text = css_text(sort_sheet(current_container(), text))
         c.insertText(text)
         c.movePosition(c.Start)
         c.endEditBlock()
         self.setTextCursor(c)
Example #42
0
 def rename_requested(self, oldname, newname):
     self.commit_all_editors_to_container()
     if guess_type(oldname) != guess_type(newname):
         args = os.path.splitext(oldname) + os.path.splitext(newname)
         if not confirm(
             _('You are changing the file type of {0}<b>{1}</b> to {2}<b>{3}</b>.'
               ' Doing so can cause problems, are you sure?').format(*args),
             'confirm-filetype-change', parent=self.gui, title=_('Are you sure?'),
             config_set=tprefs):
             return
     if urlnormalize(newname) != newname:
         if not confirm(
             _('The name you have chosen {0} contains special characters, internally'
               ' it will look like: {1}Try to use only the English alphabet [a-z], numbers [0-9],'
               ' hyphens and underscores for file names. Other characters can cause problems for '
               ' different ebook viewers. Are you sure you want to proceed?').format(
                   '<pre>%s</pre>'%newname, '<pre>%s</pre>' % urlnormalize(newname)),
             'confirm-urlunsafe-change', parent=self.gui, title=_('Are you sure?'), config_set=tprefs):
                 return
     self.add_savepoint(_('Rename %s') % oldname)
     self.gui.blocking_job(
         'rename_file', _('Renaming and updating links...'), partial(self.rename_done, oldname, newname),
         rename_files, current_container(), {oldname: newname})
Example #43
0
    def remove_format_by_id(self, book_id, fmt):
        title = self.gui.current_db.title(book_id, index_is_id=True)
        if not confirm('<p>'+(_(
            'The %(fmt)s format will be <b>permanently deleted</b> from '
            '%(title)s. Are you sure?')%dict(fmt=fmt, title=title)) +
                       '</p>', 'library_delete_specific_format', self.gui):
            return

        self.gui.library_view.model().db.remove_format(book_id, fmt,
                index_is_id=True, notify=False)
        self.gui.library_view.model().refresh_ids([book_id])
        self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
                self.gui.library_view.currentIndex())
        self.gui.tags_view.recount()
Example #44
0
 def do_paste(self, ignore_excluded_fields=False):
     rows = self.gui.library_view.selectionModel().selectedRows()
     if not rows or len(rows) == 0:
         return error_dialog(self.gui,
                             _('Cannot paste metadata'),
                             _('No books selected'),
                             show=True)
     c = QApplication.clipboard()
     md = c.mimeData()
     if not md.hasFormat('application/calibre-book-metadata'):
         return error_dialog(self.gui,
                             _('Cannot paste metadata'),
                             _('No copied metadata available'),
                             show=True)
     if len(rows) > 1:
         if not confirm(_(
                 'You are pasting metadata onto <b>multiple books</b> ({num_of_books}). Are you'
                 ' sure you want to do that?').format(
                     num_of_books=len(rows)),
                        'paste-onto-multiple',
                        parent=self.gui):
             return
     data = bytes(md.data('application/calibre-book-metadata'))
     mi = OPF(BytesIO(data),
              populate_spine=False,
              read_toc=False,
              try_to_guess_cover=False).to_book_metadata()
     mi.application_id = mi.uuid_id = None
     if ignore_excluded_fields:
         exclude = set()
     else:
         exclude = set(tweaks['exclude_fields_on_paste'])
     paste_cover = 'cover' not in exclude
     cover = md.imageData() if paste_cover else None
     exclude.discard('cover')
     for field in exclude:
         mi.set_null(field)
     db = self.gui.current_db
     book_ids = {db.id(r.row()) for r in rows}
     title_excluded = 'title' in exclude
     authors_excluded = 'authors' in exclude
     for book_id in book_ids:
         if title_excluded:
             mi.title = db.new_api.field_for('title', book_id)
         if authors_excluded:
             mi.authors = db.new_api.field_for('authors', book_id)
         db.new_api.set_metadata(book_id, mi, ignore_errors=True)
     if cover:
         db.new_api.set_cover({book_id: cover for book_id in book_ids})
     self.refresh_books_after_metadata_edit(book_ids)
Example #45
0
 def sort_css(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     if confirm(_('Sorting CSS rules can in rare cases change the effective styles applied to the book.'
                  ' Are you sure you want to proceed?'), 'edit-book-confirm-sort-css', parent=self, config_set=tprefs):
         c = self.textCursor()
         c.beginEditBlock()
         c.movePosition(c.Start), c.movePosition(c.End, c.KeepAnchor)
         text = unicode_type(c.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0')
         from calibre.ebooks.oeb.polish.css import sort_sheet
         text = css_text(sort_sheet(current_container(), text))
         c.insertText(text)
         c.movePosition(c.Start)
         c.endEditBlock()
         self.setTextCursor(c)
Example #46
0
 def reject_all_remaining(self):
     from calibre.gui2.dialogs.confirm_delete import confirm
     if not confirm(ngettext(
             'Are you sure you want to reject the remaining result?',
             'Are you sure you want to reject all {} remaining results?', len(self.ids)).format(len(self.ids)),
                    'confirm_metadata_review_reject', parent=self):
         return
     self.next_item(False)
     for id_ in self.ids:
         self.rejected_ids.add(id_)
         oldmi, newmi = self.get_metadata(id_)
         self.accepted[id_] = (False, None)
     self.ids = []
     self.accept()
Example #47
0
    def do_library_delete(self, to_delete_ids):
        view = self.gui.current_view()
        next_id = view.next_id
        # Ask the user if they want to delete the book from the library or device if it is in both.
        if self.gui.device_manager.is_device_present:
            on_device = False
            on_device_ids = self._get_selected_ids()
            for id in on_device_ids:
                res = self.gui.book_on_device(id)
                if res[0] or res[1] or res[2]:
                    on_device = True
                if on_device:
                    break
            if on_device:
                loc = confirm_location('<p>' + _('Some of the selected books are on the attached device. '
                                            '<b>Where</b> do you want the selected files deleted from?'),
                            self.gui)
                if not loc:
                    return
                elif loc == 'dev':
                    self.remove_matching_books_from_device()
                    return
                elif loc == 'both':
                    self.remove_matching_books_from_device()
        # The following will run if the selected books are not on a connected device.
        # The user has selected to delete from the library or the device and library.
        if not confirm('<p>'+ngettext(
                'The selected book will be <b>permanently deleted</b> and the files '
                'removed from your calibre library. Are you sure?',
                'The {} selected books will be <b>permanently deleted</b> and the files '
                'removed from your calibre library. Are you sure?', len(to_delete_ids)).format(len(to_delete_ids)),
                'library_delete_books', self.gui):
            return
        if len(to_delete_ids) < 5:
            try:
                view.model().delete_books_by_id(to_delete_ids)
            except IOError as err:
                if err.errno == errno.EACCES:
                    import traceback
                    fname = getattr(err, 'filename', 'file') or 'file'
                    return error_dialog(self.gui, _('Permission denied'),
                            _('Could not access %s. Is it being used by another'
                            ' program? Click "Show details" for more information.')%fname, det_msg=traceback.format_exc(),
                            show=True)

            self.library_ids_deleted2(to_delete_ids, next_id=next_id)
        else:
            self.__md = MultiDeleter(self.gui, to_delete_ids,
                    partial(self.library_ids_deleted2, next_id=next_id))
Example #48
0
    def add_formats(self, *args):
        if self.gui.stack.currentIndex() != 0:
            return
        view = self.gui.library_view
        rows = view.selectionModel().selectedRows()
        if not rows:
            return error_dialog(self.gui, _('No books selected'),
                    _('Cannot add files as no books are selected'), show=True)
        ids = [view.model().id(r) for r in rows]

        if len(ids) > 1 and not question_dialog(
                self.gui,
                _('Are you sure?'),
                _('Are you sure you want to add the same'
                  ' files to all %d books? If the format'
                  ' already exists for a book, it will be replaced.')%len(ids)):
            return

        books = choose_files(self.gui, 'add formats dialog dir',
                _('Select book files'), filters=get_filters())
        if not books:
            return

        db = view.model().db
        if len(ids) == 1:
            formats = db.formats(ids[0], index_is_id=True)
            if formats:
                formats = {x.upper() for x in formats.split(',')}
                nformats = {f.rpartition('.')[-1].upper() for f in books}
                override = formats.intersection(nformats)
                if override:
                    title = db.title(ids[0], index_is_id=True)
                    msg = ngettext(
                        'The {0} format will be replaced in the book {1}. Are you sure?',
                        'The {0} formats will be replaced in the book {1}. Are you sure?',
                        len(override)).format(', '.join(override), title)
                    if not confirm(msg, 'confirm_format_override_on_add', title=_('Are you sure?'), parent=self.gui):
                        return

        fmt_map = {os.path.splitext(fpath)[1][1:].upper():fpath for fpath in books}

        for id_ in ids:
            for fmt, fpath in fmt_map.iteritems():
                if fmt:
                    db.add_format_with_hooks(id_, fmt, fpath, index_is_id=True,
                        notify=True)
        current_idx = self.gui.library_view.currentIndex()
        if current_idx.isValid():
            view.model().current_changed(current_idx, current_idx)
 def createEditor(self, parent, option, index):
     item = self.table.item(index.row(), 0)
     if index.column() == 0:
         item = self.table.item(index.row(), 0)
         if item.is_deleted:
             return None
         return QItemDelegate.createEditor(self, parent, option, index)
     if not confirm(
             _('Do you want to undo your changes?'),
              'tag_list_editor_undo'):
             return
     item.setText(item.initial_text())
     self.table.blockSignals(True)
     self.table.item(index.row(), 2).setData(Qt.DisplayRole, '')
     self.table.blockSignals(False)
Example #50
0
 def remove_from_duplicate_exemptions(self):
     book_ids = self.gui.library_view.get_selected_ids()
     if len(book_ids) < 1:
         return error_dialog(self.gui, _('Invalid selection'),
                 _('You must select at least one book.'), show=True)
     if not confirm('<p>' + _(
              'This action will remove any duplicate exemptions for your '
              'selection. This will allow them to potentially appear '
              'as duplicates together in a future duplicate search.<p>'
              'Are you <b>sure</b> you want to proceed?'),
              'find_duplicates_remove_exemption', self.gui):
         return
     self.duplicate_finder.remove_from_book_exemptions(book_ids)
     self.duplicate_finder.remove_from_author_exemptions(book_ids)
     self.update_actions_enabled()
Example #51
0
 def delete_bookmark(self):
     item = self.bookmarks_list.current_non_removed_item
     if item is not None:
         bm = item.data(Qt.ItemDataRole.UserRole)
         if confirm(
             _('Are you sure you want to delete the bookmark: {0}?').format(bm['title']),
             'delete-bookmark-from-viewer', parent=self, config_set=vprefs
         ):
             bm['removed'] = True
             bm['timestamp'] = utcnow().isoformat()
             self.bookmarks_list.blockSignals(True)
             item.setData(Qt.ItemDataRole.UserRole, bm)
             self.bookmarks_list.blockSignals(False)
             item.setHidden(True)
             self.edited.emit(self.get_bookmarks())
 def delete_search_button_clicked(self):
     if not confirm(
             '<p>' + _('The selected search will be '
                       '<b>permanently deleted</b>. Are you sure?') +
             '</p>', 'saved_search_delete', self):
         return
     idx = self.currentIndex
     if idx < 0:
         return
     ss = saved_searches().lookup(unicode(self.currentText()))
     if ss is None:
         return
     saved_searches().delete(unicode(self.currentText()))
     self.clear()
     self.search_box.clear()
     self.changed.emit()
Example #53
0
    def add_empty_format(self, format_):
        if self.gui.stack.currentIndex() != 0:
            return
        view = self.gui.library_view
        rows = view.selectionModel().selectedRows()
        if not rows:
            return error_dialog(self.gui, _('No books selected'),
                    _('Cannot add files as no books are selected'), show=True)

        ids = [view.model().id(r) for r in rows]

        if len(ids) > 1 and not question_dialog(
                self.gui,
                _('Are you sure?'),
                _('Are you sure you want to add the same'
                  ' empty file to all %d books? If the format'
                  ' already exists for a book, it will be replaced.')%len(ids)):
            return

        db = self.gui.library_view.model().db
        if len(ids) == 1:
            formats = db.formats(ids[0], index_is_id=True)
            if formats:
                formats = {x.lower() for x in formats.split(',')}
                if format_ in formats:
                    title = db.title(ids[0], index_is_id=True)
                    msg = _('The {0} format will be replaced in the book {1}. Are you sure?').format(
                        format_, title)
                    if not confirm(msg, 'confirm_format_override_on_add', title=_('Are you sure?'),
                                   parent=self.gui):
                        return

        for id_ in ids:
            from calibre.ebooks.oeb.polish.create import create_book
            pt = PersistentTemporaryFile(suffix='.' + format_)
            pt.close()
            try:
                mi = db.new_api.get_metadata(id_, get_cover=False,
                                    get_user_categories=False, cover_as_data=False)
                create_book(mi, pt.name, fmt=format_)
                db.add_format_with_hooks(id_, format_, pt.name, index_is_id=True, notify=True)
            finally:
                os.remove(pt.name)

        current_idx = self.gui.library_view.currentIndex()
        if current_idx.isValid():
            view.model().current_changed(current_idx, current_idx)
Example #54
0
 def remove_selected_rows(self):
     self.setFocus()
     rows = self.selectionModel().selectedRows()
     if len(rows) == 0:
         return
     message = '<p>'+_('Are you sure you want to remove this book from the list?')
     if len(rows) > 1:
         message = '<p>'+_('Are you sure you want to remove the selected %d books from the list?')%len(rows)
     if not confirm(message,'epubmerge_delete_item_again', self):
         return
     first_sel_row = self.currentRow()
     for selrow in reversed(rows):
         self.removeRow(selrow.row())
     if first_sel_row < self.rowCount():
         self.select_and_scroll_to_row(first_sel_row)
     elif self.rowCount() > 0:
         self.select_and_scroll_to_row(first_sel_row - 1)
Example #55
0
    def _add_formats(self, paths, ids):
        if len(ids) > 1 and not question_dialog(
                self.gui, _('Are you sure?'),
                _('Are you sure you want to add the same'
                  ' files to all %d books? If the format'
                  ' already exists for a book, it will be replaced.') %
                len(ids)):
            return
        paths = list(map(make_long_path_useable, paths))

        db = self.gui.current_db
        if len(ids) == 1:
            formats = db.formats(ids[0], index_is_id=True)
            if formats:
                formats = {x.upper() for x in formats.split(',')}
                nformats = {f.rpartition('.')[-1].upper() for f in paths}
                override = formats.intersection(nformats)
                if override:
                    title = db.title(ids[0], index_is_id=True)
                    msg = ngettext(
                        'The {0} format will be replaced in the book {1}. Are you sure?',
                        'The {0} formats will be replaced in the book {1}. Are you sure?',
                        len(override)).format(', '.join(override), title)
                    if not confirm(msg,
                                   'confirm_format_override_on_add',
                                   title=_('Are you sure?'),
                                   parent=self.gui):
                        return

        fmt_map = {
            os.path.splitext(fpath)[1][1:].upper(): fpath
            for fpath in paths
        }

        for id_ in ids:
            for fmt, fpath in iteritems(fmt_map):
                if fmt:
                    db.add_format_with_hooks(id_,
                                             fmt,
                                             fpath,
                                             index_is_id=True,
                                             notify=True)
        current_idx = self.gui.library_view.currentIndex()
        if current_idx.isValid():
            self.gui.library_view.model().current_changed(
                current_idx, current_idx)
Example #56
0
 def remove_from_duplicate_exemptions(self):
     book_ids = self.gui.library_view.get_selected_ids()
     if len(book_ids) < 1:
         return error_dialog(self.gui,
                             _('Invalid selection'),
                             _('You must select at least one book.'),
                             show=True)
     if not confirm(
             '<p>' +
             _('This action will remove any duplicate exemptions for your '
               'selection. This will allow them to potentially appear '
               'as duplicates together in a future duplicate search.<p>'
               'Are you <b>sure</b> you want to proceed?'),
             'find_duplicates_remove_exemption', self.gui):
         return
     self.duplicate_finder.remove_from_book_exemptions(book_ids)
     self.duplicate_finder.remove_from_author_exemptions(book_ids)
     self.update_actions_enabled()
Example #57
0
    def delete_covers(self, *args):
        ids = self._get_selected_ids()
        if not ids:
            return
        if not confirm(
                '<p>' + ngettext(
                    'The cover from the selected book will be <b>permanently deleted</b>. Are you sure?',
                    'The covers from the {} selected books will be <b>permanently deleted</b>. '
                    'Are you sure?', len(ids)).format(len(ids)),
                'library_delete_covers', self.gui):
            return

        for id in ids:
            self.gui.library_view.model().db.remove_cover(id)
        self.gui.library_view.model().refresh_ids(ids)
        self.gui.library_view.model().current_changed(
            self.gui.library_view.currentIndex(),
            self.gui.library_view.currentIndex())
Example #58
0
    def start_download(self, request):
        if not self.gui:
            return

        url = unicode_type(request.url().toString(NO_URL_FORMATTING))
        cf = self.get_cookies()

        filename = get_download_filename(url, cf)
        ext = os.path.splitext(filename)[1][1:].lower()
        filename = ascii_filename(filename[:60] + '.' + ext)
        if ext not in BOOK_EXTENSIONS:
            if ext == 'acsm':
                from calibre.gui2.dialogs.confirm_delete import confirm
                if not confirm(
                        '<p>' +
                        _('This e-book is a DRMed EPUB file.  '
                          'You will be prompted to save this file to your '
                          'computer. Once it is saved, open it with '
                          '<a href="https://www.adobe.com/solutions/ebook/digital-editions.html">'
                          'Adobe Digital Editions</a> (ADE).<p>ADE, in turn '
                          'will download the actual e-book, which will be a '
                          '.epub file. You can add this book to calibre '
                          'using "Add Books" and selecting the file from '
                          'the ADE library folder.'), 'acsm_download', self):
                    return
            name = choose_save_file(
                self,
                'web-store-download-unknown',
                _('File is not a supported e-book type. Save to disk?'),
                initial_filename=filename)
            if name:
                self.gui.download_ebook(url,
                                        cf,
                                        name,
                                        name,
                                        False,
                                        create_browser=self.create_browser)
        else:
            show_download_info(filename, self)
            self.gui.download_ebook(url,
                                    cf,
                                    filename,
                                    tags=self.tags,
                                    create_browser=self.create_browser)
Example #59
0
 def files_dropped_on_book(self, event, paths, cid=None, do_confirm=True):
     accept = False
     if self.gui.current_view() is not self.gui.library_view:
         return
     db = self.gui.library_view.model().db
     cover_changed = False
     current_idx = self.gui.library_view.currentIndex()
     if cid is None:
         if not current_idx.isValid():
             return
         cid = db.id(current_idx.row()) if cid is None else cid
     formats = []
     from calibre.gui2.dnd import image_extensions
     for path in paths:
         ext = os.path.splitext(path)[1].lower()
         if ext:
             ext = ext[1:]
         if ext in image_extensions():
             pmap = QPixmap()
             pmap.load(path)
             if not pmap.isNull():
                 accept = True
                 db.set_cover(cid, pmap)
                 cover_changed = True
         else:
             formats.append((ext, path))
             accept = True
     if accept and event is not None:
         event.accept()
     if do_confirm and formats:
         if not confirm(_(
                 'You have dropped some files onto the book <b>%s</b>. This will'
                 ' add or replace the files for this book. Do you want to proceed?'
         ) % db.title(cid, index_is_id=True),
                        'confirm_drop_on_book',
                        parent=self.gui):
             formats = []
     for ext, path in formats:
         db.add_format_with_hooks(cid, ext, path, index_is_id=True)
     if current_idx.isValid():
         self.gui.library_view.model().current_changed(
             current_idx, current_idx)
     if cover_changed:
         self.gui.refresh_cover_browser()