mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Save to disk implemented.
This commit is contained in:
parent
fe2336d227
commit
a1c8fcff51
@ -162,6 +162,15 @@ class Device(object):
|
|||||||
'''
|
'''
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def get_file(self, path, outfile, end_session=True):
|
||||||
|
'''
|
||||||
|
Read the file at C{path} on the device and write it to outfile.
|
||||||
|
@param outfile: file object like C{sys.stdout} or the result of an C{open} call
|
||||||
|
'''
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BookList(list):
|
class BookList(list):
|
||||||
'''
|
'''
|
||||||
A list of books. Each Book object must have the fields:
|
A list of books. Each Book object must have the fields:
|
||||||
|
@ -1231,7 +1231,7 @@ class HTMLConverter(object):
|
|||||||
except Exception, err:
|
except Exception, err:
|
||||||
print 'WARNING: An error occurred while processing a table:', err
|
print 'WARNING: An error occurred while processing a table:', err
|
||||||
print 'Ignoring table markup for table:'
|
print 'Ignoring table markup for table:'
|
||||||
print str(tag)[:100]
|
print str(tag)[:300]
|
||||||
self.in_table = False
|
self.in_table = False
|
||||||
self.process_children(tag, tag_css)
|
self.process_children(tag, tag_css)
|
||||||
else:
|
else:
|
||||||
|
@ -186,6 +186,13 @@ class FileDialog(QObject):
|
|||||||
settings.setValue(self.dialog_name, QVariant(self.fd.saveState()))
|
settings.setValue(self.dialog_name, QVariant(self.fd.saveState()))
|
||||||
|
|
||||||
|
|
||||||
|
def choose_dir(window, name, title):
|
||||||
|
settings = QSettings()
|
||||||
|
dir = settings.value(name, QVariant(os.path.expanduser('~'))).toString()
|
||||||
|
dir = qstring_to_unicode(QFileDialog.getExistingDirectory(window, title, dir))
|
||||||
|
if os.path.exists(dir):
|
||||||
|
return dir
|
||||||
|
|
||||||
def choose_files(window, name, title,
|
def choose_files(window, name, title,
|
||||||
filters=[], all_files=True, select_only_single_file=False):
|
filters=[], all_files=True, select_only_single_file=False):
|
||||||
'''
|
'''
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
## You should have received a copy of the GNU General Public License along
|
## You should have received a copy of the GNU General Public License along
|
||||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
|
||||||
import sys
|
import sys, os
|
||||||
|
|
||||||
from PyQt4.QtCore import QThread, SIGNAL, QObject
|
from PyQt4.QtCore import QThread, SIGNAL, QObject
|
||||||
|
|
||||||
@ -111,9 +111,21 @@ class DeviceManager(QObject):
|
|||||||
def delete_books_func(self):
|
def delete_books_func(self):
|
||||||
'''Remove books from device'''
|
'''Remove books from device'''
|
||||||
def delete_books(updater, paths):
|
def delete_books(updater, paths):
|
||||||
'''Delete books from device'''
|
'''Remove books from device'''
|
||||||
self.device.delete_books(paths, end_session=True)
|
self.device.delete_books(paths, end_session=True)
|
||||||
return delete_books
|
return delete_books
|
||||||
|
|
||||||
def remove_books_from_metadata(self, paths, booklists):
|
def remove_books_from_metadata(self, paths, booklists):
|
||||||
self.device_class.remove_books_from_metadata(paths, booklists)
|
self.device_class.remove_books_from_metadata(paths, booklists)
|
||||||
|
|
||||||
|
def save_books_func(self):
|
||||||
|
'''Copy books from device to disk'''
|
||||||
|
def save_books(updater, paths, target):
|
||||||
|
'''Copy books from device to disk'''
|
||||||
|
self.device.set_progress_reporter(updater)
|
||||||
|
for path in paths:
|
||||||
|
name = path.rpartition('/')[2]
|
||||||
|
f = open(os.path.join(target, name), 'wb')
|
||||||
|
self.device.get_file(path, f)
|
||||||
|
f.close()
|
||||||
|
return save_books
|
@ -29,6 +29,7 @@
|
|||||||
<file>images/mimetypes/zip.svg</file>
|
<file>images/mimetypes/zip.svg</file>
|
||||||
<file>images/plus.svg</file>
|
<file>images/plus.svg</file>
|
||||||
<file>images/reader.svg</file>
|
<file>images/reader.svg</file>
|
||||||
|
<file>images/save.svg</file>
|
||||||
<file>images/sd.svg</file>
|
<file>images/sd.svg</file>
|
||||||
<file>images/sync.svg</file>
|
<file>images/sync.svg</file>
|
||||||
<file>images/trash.svg</file>
|
<file>images/trash.svg</file>
|
||||||
|
@ -103,6 +103,10 @@ 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):
|
||||||
|
rows = [row.row() for row in rows]
|
||||||
|
self.db.export_to_dir(path, rows)
|
||||||
|
|
||||||
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 ]
|
||||||
for id in ids:
|
for id in ids:
|
||||||
|
@ -19,13 +19,13 @@ from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
|
|||||||
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox
|
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox
|
||||||
from PyQt4.QtSvg import QSvgRenderer
|
from PyQt4.QtSvg import QSvgRenderer
|
||||||
|
|
||||||
from libprs500 import __version__, __appname__, iswindows, isosx
|
from libprs500 import __version__, __appname__
|
||||||
from libprs500.ebooks.metadata.meta import get_metadata
|
from libprs500.ebooks.metadata.meta import get_metadata
|
||||||
from libprs500.devices.errors import FreeSpaceError
|
from libprs500.devices.errors import FreeSpaceError
|
||||||
from libprs500.devices.interface import Device
|
from libprs500.devices.interface import Device
|
||||||
from libprs500.gui2 import APP_TITLE, warning_dialog, choose_files, error_dialog, \
|
from libprs500.gui2 import APP_TITLE, warning_dialog, choose_files, error_dialog, \
|
||||||
initialize_file_icon_provider, BOOK_EXTENSIONS, \
|
initialize_file_icon_provider, BOOK_EXTENSIONS, \
|
||||||
pixmap_to_data
|
pixmap_to_data, choose_dir
|
||||||
from libprs500.gui2.main_ui import Ui_MainWindow
|
from libprs500.gui2.main_ui import Ui_MainWindow
|
||||||
from libprs500.gui2.device import DeviceDetector, DeviceManager
|
from libprs500.gui2.device import DeviceDetector, DeviceManager
|
||||||
from libprs500.gui2.status import StatusBar
|
from libprs500.gui2.status import StatusBar
|
||||||
@ -95,7 +95,7 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
QObject.connect(self.action_sync, SIGNAL("triggered(bool)"), self.sync_to_main_memory)
|
QObject.connect(self.action_sync, SIGNAL("triggered(bool)"), self.sync_to_main_memory)
|
||||||
QObject.connect(sm.actions()[0], SIGNAL('triggered(bool)'), self.sync_to_main_memory)
|
QObject.connect(sm.actions()[0], SIGNAL('triggered(bool)'), self.sync_to_main_memory)
|
||||||
QObject.connect(sm.actions()[1], SIGNAL('triggered(bool)'), self.sync_to_card)
|
QObject.connect(sm.actions()[1], SIGNAL('triggered(bool)'), self.sync_to_card)
|
||||||
|
QObject.connect(self.action_save, SIGNAL("triggered(bool)"), self.save_to_disk)
|
||||||
self.action_sync.setMenu(sm)
|
self.action_sync.setMenu(sm)
|
||||||
self.action_edit.setMenu(md)
|
self.action_edit.setMenu(md)
|
||||||
self.tool_bar.addAction(self.action_sync)
|
self.tool_bar.addAction(self.action_sync)
|
||||||
@ -423,6 +423,29 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
|
############################## Save to disk ################################
|
||||||
|
def save_to_disk(self, checked):
|
||||||
|
rows = self.current_view().selectionModel().selectedRows()
|
||||||
|
if not rows or len(rows) == 0:
|
||||||
|
d = error_dialog(self.window, 'Cannot save to disk', 'No books selected')
|
||||||
|
d.exec_()
|
||||||
|
return
|
||||||
|
dir = choose_dir(self.window, 'save to disk dialog', 'Choose destination directory')
|
||||||
|
if not dir:
|
||||||
|
return
|
||||||
|
if self.current_view() == self.library_view:
|
||||||
|
self.current_view().model().save_to_disk(rows, dir)
|
||||||
|
else:
|
||||||
|
paths = self.current_view().model().paths(rows)
|
||||||
|
self.job_manager.run_device_job(self.books_saved,
|
||||||
|
self.device_manager.save_books_func(), paths, dir)
|
||||||
|
|
||||||
|
def books_saved(self, id, description, result, exception, formatted_traceback):
|
||||||
|
if exception:
|
||||||
|
self.device_job_exception(id, description, exception, formatted_traceback)
|
||||||
|
return
|
||||||
|
|
||||||
|
############################################################################
|
||||||
def location_selected(self, location):
|
def location_selected(self, location):
|
||||||
'''
|
'''
|
||||||
Called when a location icon is clicked (e.g. Library)
|
Called when a location icon is clicked (e.g. Library)
|
||||||
|
@ -319,6 +319,7 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<addaction name="action_add" />
|
<addaction name="action_add" />
|
||||||
<addaction name="action_del" />
|
<addaction name="action_del" />
|
||||||
|
<addaction name="action_save" />
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar" >
|
<widget class="QStatusBar" name="statusBar" >
|
||||||
<property name="mouseTracking" >
|
<property name="mouseTracking" >
|
||||||
@ -378,6 +379,14 @@
|
|||||||
<string>Send to device</string>
|
<string>Send to device</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_save" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="images.qrc" >:/images/save.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Save to disk</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
@ -12,11 +12,12 @@
|
|||||||
## You should have received a copy of the GNU General Public License along
|
## You should have received a copy of the GNU General Public License along
|
||||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
from libprs500 import __appname__
|
||||||
"""
|
"""
|
||||||
Backend that implements storage of ebooks in an sqlite database.
|
Backend that implements storage of ebooks in an sqlite database.
|
||||||
"""
|
"""
|
||||||
import sqlite3 as sqlite
|
import sqlite3 as sqlite
|
||||||
import datetime, re
|
import datetime, re, os
|
||||||
from zlib import compress, decompress
|
from zlib import compress, decompress
|
||||||
|
|
||||||
class Concatenate(object):
|
class Concatenate(object):
|
||||||
@ -898,3 +899,31 @@ class LibraryDatabase(object):
|
|||||||
pass
|
pass
|
||||||
self.conn.execute('DELETE FROM books WHERE id=?', (id,))
|
self.conn.execute('DELETE FROM books WHERE id=?', (id,))
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
|
def export_to_dir(self, dir, indices):
|
||||||
|
by_author = {}
|
||||||
|
for index in indices:
|
||||||
|
id = self.id(index)
|
||||||
|
au = self.conn.execute('SELECT concat(sort) FROM authors WHERE authors.id IN (SELECT author from books_authors_link WHERE book=?)', (id,)).fetchone()[0]
|
||||||
|
if not by_author.has_key(au):
|
||||||
|
by_author[au] = []
|
||||||
|
by_author[au].append(index)
|
||||||
|
for au in by_author.keys():
|
||||||
|
apath = os.path.join(dir, au)
|
||||||
|
if not os.path.exists(apath):
|
||||||
|
os.mkdir(apath)
|
||||||
|
for idx in by_author[au]:
|
||||||
|
title = self.title(idx)
|
||||||
|
tpath = os.path.join(apath, title)
|
||||||
|
id = str(self.id(idx))
|
||||||
|
if not os.path.exists(tpath):
|
||||||
|
os.mkdir(tpath)
|
||||||
|
for fmt in self.formats(idx).split(','):
|
||||||
|
data = self.format(idx, fmt)
|
||||||
|
f = open(os.path.join(tpath, __appname__+'_'+id+'.'+fmt.lower()), 'wb')
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
db = LibraryDatabase('/home/kovid/library1.db')
|
||||||
|
db.refresh('title', True)
|
||||||
|
db.export_to_dir('/tmp/test', range(1, 10))
|
Loading…
x
Reference in New Issue
Block a user