Add action to save only specified format when saving to disk

This commit is contained in:
Kovid Goyal 2008-06-25 19:38:57 -07:00
parent 476e9371bb
commit 7b498bf908
7 changed files with 161 additions and 127 deletions

View File

@ -15,6 +15,6 @@ class ConversionError(Exception):
class UnknownFormatError(Exception): class UnknownFormatError(Exception):
pass pass
BOOK_EXTENSIONS = ['lrf', 'lrx', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'xhtm', BOOK_EXTENSIONS = ['lrf', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'xhtm',
'html', 'xhtml', 'epub', 'pdf', 'prc', 'mobi', 'azw', 'html', 'xhtml', 'epub', 'pdf', 'prc', 'mobi', 'azw',
'epub', 'fb2', 'djvu'] 'epub', 'fb2', 'djvu', 'lrx']

View File

@ -222,7 +222,7 @@ class MobiReader(object):
tocobj = TOC() tocobj = TOC()
for a in soup.findAll('a', href=True): for a in soup.findAll('a', href=True):
try: try:
text = ''.join(a.findAll(text=True)) text = ''.join(a.findAll(text=True)).strip()
except: except:
text = '' text = ''
tocobj.add_item(toc.partition('#')[0], a['href'][1:], text) tocobj.add_item(toc.partition('#')[0], a['href'][1:], text)

View File

@ -3,12 +3,13 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import os import os
from PyQt4.QtGui import QDialog, QMessageBox, QListWidgetItem, QIcon from PyQt4.QtGui import QDialog, QMessageBox, QListWidgetItem, QIcon
from PyQt4.QtCore import SIGNAL, QTimer, Qt, QSize from PyQt4.QtCore import SIGNAL, QTimer, Qt, QSize, QVariant
from calibre import islinux, Settings from calibre import islinux, Settings
from calibre.gui2.dialogs.config_ui import Ui_Dialog from calibre.gui2.dialogs.config_ui import Ui_Dialog
from calibre.gui2 import qstring_to_unicode, choose_dir, error_dialog from calibre.gui2 import qstring_to_unicode, choose_dir, error_dialog
from calibre.gui2.widgets import FilenamePattern from calibre.gui2.widgets import FilenamePattern
from calibre.ebooks import BOOK_EXTENSIONS
@ -59,6 +60,11 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2) self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2)
self.show_toolbar_text.setChecked(settings.get('show text in toolbar', True)) self.show_toolbar_text.setChecked(settings.get('show text in toolbar', True))
for ext in BOOK_EXTENSIONS:
self.single_format.addItem(ext.upper(), QVariant(ext))
single_format = settings.get('save to disk single format', 'lrf')
self.single_format.setCurrentIndex(BOOK_EXTENSIONS.index(single_format))
def compact(self, toggled): def compact(self, toggled):
d = Vacuum(self, self.db) d = Vacuum(self, self.db)
@ -89,6 +95,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
settings.set('show text in toolbar', bool(self.show_toolbar_text.isChecked())) settings.set('show text in toolbar', bool(self.show_toolbar_text.isChecked()))
pattern = self.filename_pattern.commit() pattern = self.filename_pattern.commit()
settings.set('filename pattern', pattern) settings.set('filename pattern', pattern)
settings.set('save to disk single format', BOOK_EXTENSIONS[self.single_format.currentIndex()])
if not path or not os.path.exists(path) or not os.path.isdir(path): if not path or not os.path.exists(path) or not os.path.isdir(path):
d = error_dialog(self, _('Invalid database location'), _('Invalid database location ')+path+_('<br>Must be a directory.')) d = error_dialog(self, _('Invalid database location'), _('Invalid database location ')+path+_('<br>Must be a directory.'))

View File

@ -1,4 +1,5 @@
<ui version="4.0" > <ui version="4.0" >
<author>Kovid Goyal</author>
<class>Dialog</class> <class>Dialog</class>
<widget class="QDialog" name="Dialog" > <widget class="QDialog" name="Dialog" >
<property name="geometry" > <property name="geometry" >
@ -76,18 +77,10 @@
<property name="currentIndex" > <property name="currentIndex" >
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="page" > <widget class="QWidget" name="page_3" >
<property name="geometry" > <layout class="QVBoxLayout" name="verticalLayout" >
<rect> <item>
<x>0</x> <layout class="QVBoxLayout" name="_2" >
<y>0</y>
<width>583</width>
<height>625</height>
</rect>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<layout class="QVBoxLayout" >
<item> <item>
<widget class="QLabel" name="label" > <widget class="QLabel" name="label" >
<property name="text" > <property name="text" >
@ -99,7 +92,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" > <layout class="QHBoxLayout" name="_3" >
<item> <item>
<widget class="QLineEdit" name="location" /> <widget class="QLineEdit" name="location" />
</item> </item>
@ -121,7 +114,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="0" > <item>
<widget class="QCheckBox" name="roman_numerals" > <widget class="QCheckBox" name="roman_numerals" >
<property name="text" > <property name="text" >
<string>Use &amp;Roman numerals for series number</string> <string>Use &amp;Roman numerals for series number</string>
@ -131,9 +124,35 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0" > <item>
<layout class="QHBoxLayout" > <layout class="QGridLayout" name="gridLayout_2" >
<item> <item row="0" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Format for &amp;single file save:</string>
</property>
<property name="buddy" >
<cstring>single_format</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QComboBox" name="single_format" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>&amp;Priority for conversion jobs:</string>
</property>
<property name="buddy" >
<cstring>priority</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QComboBox" name="priority" />
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_2" > <widget class="QLabel" name="label_2" >
<property name="text" > <property name="text" >
<string>Default network &amp;timeout:</string> <string>Default network &amp;timeout:</string>
@ -143,7 +162,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="2" column="1" >
<widget class="QSpinBox" name="timeout" > <widget class="QSpinBox" name="timeout" >
<property name="toolTip" > <property name="toolTip" >
<string>Set the default timeout for network fetches (i.e. anytime we go out to the internet to get information)</string> <string>Set the default timeout for network fetches (i.e. anytime we go out to the internet to get information)</string>
@ -164,31 +183,78 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="3" column="0" > <item>
<layout class="QHBoxLayout" > <widget class="QGroupBox" name="groupBox_2" >
<item> <property name="title" >
<widget class="QLabel" name="label_3" > <string>Toolbar</string>
<property name="text" > </property>
<string>&amp;Priority for conversion jobs:</string> <layout class="QGridLayout" name="gridLayout" >
</property> <item row="0" column="1" >
<property name="buddy" > <widget class="QComboBox" name="toolbar_button_size" >
<cstring>priority</cstring> <item>
</property> <property name="text" >
</widget> <string>Large</string>
</item> </property>
<item> </item>
<widget class="QComboBox" name="priority" /> <item>
</item> <property name="text" >
</layout> <string>Medium</string>
</property>
</item>
<item>
<property name="text" >
<string>Small</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>&amp;Button size in toolbar</string>
</property>
<property name="buddy" >
<cstring>toolbar_button_size</cstring>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QCheckBox" name="show_toolbar_text" >
<property name="text" >
<string>Show &amp;text in toolbar buttons</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item> </item>
<item row="6" column="0" > <item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Select visible &amp;columns in library view</string>
</property>
<layout class="QGridLayout" name="_4" >
<item row="0" column="0" >
<widget class="QListWidget" name="columns" >
<property name="selectionMode" >
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="dirs_box" > <widget class="QGroupBox" name="dirs_box" >
<property name="title" > <property name="title" >
<string>Frequently used directories</string> <string>Frequently used directories</string>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout" name="_5" >
<item row="0" column="0" > <item row="0" column="0" >
<layout class="QHBoxLayout" > <layout class="QHBoxLayout" name="_6" >
<item> <item>
<widget class="QListWidget" name="directory_list" > <widget class="QListWidget" name="directory_list" >
<property name="alternatingRowColors" > <property name="alternatingRowColors" >
@ -203,7 +269,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" > <layout class="QVBoxLayout" name="_7" >
<item> <item>
<spacer> <spacer>
<property name="orientation" > <property name="orientation" >
@ -278,83 +344,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="7" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>392</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" >
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Select visible &amp;columns in library view</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QListWidget" name="columns" >
<property name="selectionMode" >
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0" >
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Toolbar</string>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="1" >
<widget class="QComboBox" name="toolbar_button_size" >
<item>
<property name="text" >
<string>Large</string>
</property>
</item>
<item>
<property name="text" >
<string>Medium</string>
</property>
</item>
<item>
<property name="text" >
<string>Small</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>&amp;Button size in toolbar</string>
</property>
<property name="buddy" >
<cstring>toolbar_button_size</cstring>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QCheckBox" name="show_toolbar_text" >
<property name="text" >
<string>Show &amp;text in toolbar buttons</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="page_2" > <widget class="QWidget" name="page_2" >
@ -362,8 +351,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>583</width> <width>595</width>
<height>625</height> <height>638</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" > <layout class="QVBoxLayout" >

View File

@ -150,9 +150,13 @@ class BooksModel(QAbstractTableModel):
''' Return list indices of all cells in index.row()''' ''' Return list indices of all cells in index.row()'''
return [ self.index(index.row(), c) for c in range(self.columnCount(None))] return [ self.index(index.row(), c) for c in range(self.columnCount(None))]
def save_to_disk(self, rows, path, single_dir=False): def save_to_disk(self, rows, path, single_dir=False, single_format=None):
rows = [row.row() for row in rows] rows = [row.row() for row in rows]
self.db.export_to_dir(path, rows, self.sorted_on[0] == 1, single_dir=single_dir) if single_format is None:
return self.db.export_to_dir(path, rows, self.sorted_on[0] == 1, single_dir=single_dir)
else:
return self.db.export_single_format_to_dir(path, rows, single_format)
def delete_books(self, indices): def delete_books(self, indices):
ids = [ self.id(i) for i in indices ] ids = [ self.id(i) for i in indices ]

View File

@ -136,6 +136,7 @@ class Main(MainWindow, Ui_MainWindow):
self.save_menu = QMenu() self.save_menu = QMenu()
self.save_menu.addAction(_('Save to disk')) self.save_menu.addAction(_('Save to disk'))
self.save_menu.addAction(_('Save to disk in a single directory')) self.save_menu.addAction(_('Save to disk in a single directory'))
self.save_menu.addAction(_('Save only %s format to disk')%Settings().get('save to disk single format', 'lrf').upper())
self.view_menu = QMenu() self.view_menu = QMenu()
self.view_menu.addAction(_('View')) self.view_menu.addAction(_('View'))
@ -144,6 +145,7 @@ class Main(MainWindow, Ui_MainWindow):
QObject.connect(self.action_save, SIGNAL("triggered(bool)"), self.save_to_disk) QObject.connect(self.action_save, SIGNAL("triggered(bool)"), self.save_to_disk)
QObject.connect(self.save_menu.actions()[0], SIGNAL("triggered(bool)"), self.save_to_disk) QObject.connect(self.save_menu.actions()[0], SIGNAL("triggered(bool)"), self.save_to_disk)
QObject.connect(self.save_menu.actions()[1], SIGNAL("triggered(bool)"), self.save_to_single_dir) QObject.connect(self.save_menu.actions()[1], SIGNAL("triggered(bool)"), self.save_to_single_dir)
QObject.connect(self.save_menu.actions()[2], SIGNAL("triggered(bool)"), self.save_single_format_to_disk)
QObject.connect(self.action_view, SIGNAL("triggered(bool)"), self.view_book) QObject.connect(self.action_view, SIGNAL("triggered(bool)"), self.view_book)
QObject.connect(self.view_menu.actions()[0], SIGNAL("triggered(bool)"), self.view_book) QObject.connect(self.view_menu.actions()[0], SIGNAL("triggered(bool)"), self.view_book)
QObject.connect(self.view_menu.actions()[1], SIGNAL("triggered(bool)"), self.view_specific_format) QObject.connect(self.view_menu.actions()[1], SIGNAL("triggered(bool)"), self.view_specific_format)
@ -662,20 +664,32 @@ class Main(MainWindow, Ui_MainWindow):
############################################################################ ############################################################################
############################## Save to disk ################################ ############################## Save to disk ################################
def save_single_format_to_disk(self, checked):
self.save_to_disk(checked, True, Settings().get('save to disk single format', 'lrf'))
def save_to_single_dir(self, checked): def save_to_single_dir(self, checked):
self.save_to_disk(checked, True) self.save_to_disk(checked, True)
def save_to_disk(self, checked, single_dir=False): def save_to_disk(self, checked, single_dir=False, single_format=None):
rows = self.current_view().selectionModel().selectedRows() rows = self.current_view().selectionModel().selectedRows()
if not rows or len(rows) == 0: if not rows or len(rows) == 0:
d = error_dialog(self, _('Cannot save to disk'), _('No books selected')) d = error_dialog(self, _('Cannot save to disk'), _('No books selected'))
d.exec_() d.exec_()
return return
dir = choose_dir(self, 'save to disk dialog', ('Choose destination directory')) dir = choose_dir(self, 'save to disk dialog', ('Choose destination directory'))
if not dir: if not dir:
return return
if self.current_view() == self.library_view: if self.current_view() == self.library_view:
self.current_view().model().save_to_disk(rows, dir, single_dir=single_dir) failures = self.current_view().model().save_to_disk(rows, dir,
single_dir=single_dir, single_format=single_format)
if failures and single_format is not None:
msg = _('<p>Could not save the following books to disk, because the %s format is not available for them:<ul>')%single_format.upper()
for f in failures:
msg += '<li>%s</li>'%f[1]
msg += '</ul>'
warning_dialog(self, _('Could not save some ebooks'), msg).exec_()
QDesktopServices.openUrl(QUrl('file:'+dir))
else: else:
paths = self.current_view().model().paths(rows) paths = self.current_view().model().paths(rows)
self.job_manager.run_device_job(self.books_saved, self.job_manager.run_device_job(self.books_saved,

View File

@ -1549,6 +1549,25 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
duplicates.extend(res) duplicates.extend(res)
return duplicates return duplicates
def export_single_format_to_dir(self, dir, indices, format, index_is_id=False):
if not index_is_id:
indices = map(self.id, indices)
failures = []
for id in indices:
try:
data = self.format(id, format, index_is_id=True)
except:
failures.append((id, self.title(id, index_is_id=True)))
title = self.title(id, index_is_id=True)
au = self.authors(id, index_is_id=True)
if not au:
au = _('Unknown')
fname = '%s - %s.%s'%(title, au, format.lower())
fname = sanitize_file_name(fname)
open(os.path.join(dir, fname), 'wb').write(data)
return failures
class SearchToken(object): class SearchToken(object):